rex 2.0.8 → 2.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rex.rb +1 -0
- data/lib/rex/arch.rb +5 -0
- data/lib/rex/arch/x86.rb +19 -5
- data/lib/rex/arch/zarch.rb +17 -0
- data/lib/rex/compat.rb +5 -4
- data/lib/rex/constants.rb +3 -1
- data/lib/rex/encoder/alpha2/alpha_mixed.rb +70 -9
- data/lib/rex/encoder/alpha2/alpha_upper.rb +67 -8
- data/lib/rex/exploitation/cmdstager.rb +1 -0
- data/lib/rex/exploitation/cmdstager/certutil.rb +115 -0
- data/lib/rex/exploitation/cmdstager/echo.rb +6 -3
- data/lib/rex/exploitation/egghunter.rb +1 -1
- data/lib/rex/google/geolocation.rb +68 -0
- data/lib/rex/io/bidirectional_pipe.rb +0 -4
- data/lib/rex/java/serialization.rb +2 -0
- data/lib/rex/java/serialization/decode_error.rb +11 -0
- data/lib/rex/java/serialization/encode_error.rb +11 -0
- data/lib/rex/java/serialization/model.rb +2 -0
- data/lib/rex/java/serialization/model/annotation.rb +3 -3
- data/lib/rex/java/serialization/model/block_data.rb +3 -3
- data/lib/rex/java/serialization/model/block_data_long.rb +3 -3
- data/lib/rex/java/serialization/model/class_desc.rb +6 -6
- data/lib/rex/java/serialization/model/contents.rb +17 -10
- data/lib/rex/java/serialization/model/field.rb +12 -11
- data/lib/rex/java/serialization/model/long_utf.rb +3 -3
- data/lib/rex/java/serialization/model/new_array.rb +22 -23
- data/lib/rex/java/serialization/model/new_class.rb +57 -0
- data/lib/rex/java/serialization/model/new_class_desc.rb +15 -16
- data/lib/rex/java/serialization/model/new_enum.rb +5 -5
- data/lib/rex/java/serialization/model/new_object.rb +22 -17
- data/lib/rex/java/serialization/model/proxy_class_desc.rb +109 -0
- data/lib/rex/java/serialization/model/reference.rb +4 -4
- data/lib/rex/java/serialization/model/stream.rb +7 -7
- data/lib/rex/java/serialization/model/utf.rb +3 -3
- data/lib/rex/json_hash_file.rb +94 -0
- data/lib/rex/logging/log_sink.rb +1 -0
- data/lib/rex/logging/sinks/timestamp_flatfile.rb +21 -0
- data/lib/rex/parser/appscan_nokogiri.rb +13 -23
- data/lib/rex/parser/fs/ntfs.rb +10 -5
- data/lib/rex/parser/nmap_nokogiri.rb +3 -1
- data/lib/rex/parser/openvas_nokogiri.rb +70 -73
- data/lib/rex/parser/winscp.rb +108 -0
- data/lib/rex/parser/x509_certificate.rb +92 -0
- data/lib/rex/payloads.rb +0 -1
- data/lib/rex/payloads/meterpreter/config.rb +154 -0
- data/lib/rex/payloads/meterpreter/uri_checksum.rb +136 -0
- data/lib/rex/post/meterpreter.rb +1 -1
- data/lib/rex/post/meterpreter/client.rb +26 -3
- data/lib/rex/post/meterpreter/client_core.rb +387 -75
- data/lib/rex/post/meterpreter/extensions/android/android.rb +127 -37
- data/lib/rex/post/meterpreter/extensions/android/tlv.rb +46 -25
- data/lib/rex/post/meterpreter/extensions/extapi/extapi.rb +4 -0
- data/lib/rex/post/meterpreter/extensions/extapi/ntds/ntds.rb +39 -0
- data/lib/rex/post/meterpreter/extensions/extapi/pageant/pageant.rb +44 -0
- data/lib/rex/post/meterpreter/extensions/extapi/tlv.rb +9 -0
- data/lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb +16 -1
- data/lib/rex/post/meterpreter/extensions/priv/priv.rb +1 -1
- data/lib/rex/post/meterpreter/extensions/python/python.rb +114 -0
- data/lib/rex/post/meterpreter/extensions/python/tlv.rb +21 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb +17 -14
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +33 -12
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/mount.rb +57 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_kernel32.rb +3 -3
- data/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb +3 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb +2 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +16 -3
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb +29 -6
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key.rb +5 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +18 -6
- data/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +2 -2
- data/lib/rex/post/meterpreter/extensions/stdapi/webcam/webcam.rb +34 -36
- data/lib/rex/post/meterpreter/packet.rb +29 -0
- data/lib/rex/post/meterpreter/packet_dispatcher.rb +20 -7
- data/lib/rex/post/meterpreter/ui/console.rb +1 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +230 -72
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +544 -34
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb +188 -57
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb +115 -93
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks/dhcp.rb +1 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/mimikatz.rb +1 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/elevate.rb +49 -15
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/timestomp.rb +11 -2
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/python.rb +187 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +324 -133
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +52 -2
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +68 -65
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui.rb +9 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/webcam.rb +113 -118
- data/lib/rex/post/meterpreter/ui/console/interactive_channel.rb +3 -0
- data/lib/rex/powershell.rb +62 -0
- data/lib/rex/powershell/command.rb +359 -0
- data/lib/rex/{exploitation/powershell → powershell}/function.rb +0 -2
- data/lib/rex/{exploitation/powershell → powershell}/obfu.rb +0 -2
- data/lib/rex/{exploitation/powershell → powershell}/output.rb +11 -5
- data/lib/rex/{exploitation/powershell → powershell}/param.rb +0 -2
- data/lib/rex/powershell/parser.rb +182 -0
- data/lib/rex/powershell/payload.rb +78 -0
- data/lib/rex/{exploitation/powershell → powershell}/psh_methods.rb +16 -2
- data/lib/rex/{exploitation/powershell → powershell}/script.rb +2 -4
- data/lib/rex/proto/dcerpc/client.rb +6 -6
- data/lib/rex/proto/dcerpc/exceptions.rb +26 -0
- data/lib/rex/proto/http/client.rb +3 -3
- data/lib/rex/proto/http/client_request.rb +0 -5
- data/lib/rex/proto/http/response.rb +86 -0
- data/lib/rex/proto/ipmi/utils.rb +30 -26
- data/lib/rex/proto/kerberos/client.rb +1 -1
- data/lib/rex/proto/kerberos/model/kdc_request.rb +2 -2
- data/lib/rex/proto/rfb/client.rb +8 -3
- data/lib/rex/proto/rfb/constants.rb +1 -1
- data/lib/rex/proto/rmi.rb +2 -0
- data/lib/rex/proto/rmi/decode_error.rb +10 -0
- data/lib/rex/proto/rmi/exception.rb +10 -0
- data/lib/rex/proto/rmi/model.rb +5 -0
- data/lib/rex/proto/rmi/model/call.rb +4 -4
- data/lib/rex/proto/rmi/model/call_data.rb +137 -0
- data/lib/rex/proto/rmi/model/dgc_ack.rb +2 -2
- data/lib/rex/proto/rmi/model/element.rb +26 -11
- data/lib/rex/proto/rmi/model/output_header.rb +4 -4
- data/lib/rex/proto/rmi/model/ping.rb +2 -2
- data/lib/rex/proto/rmi/model/ping_ack.rb +2 -2
- data/lib/rex/proto/rmi/model/protocol_ack.rb +2 -2
- data/lib/rex/proto/rmi/model/return_data.rb +5 -5
- data/lib/rex/proto/rmi/model/return_value.rb +124 -0
- data/lib/rex/proto/rmi/model/unique_identifier.rb +77 -0
- data/lib/rex/proto/steam.rb +3 -0
- data/lib/rex/proto/steam/message.rb +125 -0
- data/lib/rex/proto/tftp/client.rb +35 -14
- data/lib/rex/random_identifier_generator.rb +2 -0
- data/lib/rex/ropbuilder.rb +1 -1
- data/lib/rex/socket/parameters.rb +9 -0
- data/lib/rex/socket/ssl_tcp.rb +25 -41
- data/lib/rex/socket/ssl_tcp_server.rb +10 -21
- data/lib/rex/sslscan/result.rb +20 -1
- data/lib/rex/text.rb +241 -55
- data/lib/rex/ui/output.rb +0 -3
- data/lib/rex/ui/subscriber.rb +0 -10
- data/lib/rex/ui/text/color.rb +9 -0
- data/lib/rex/ui/text/dispatcher_shell.rb +1 -0
- data/lib/rex/ui/text/output.rb +15 -4
- data/lib/rex/ui/text/output/file.rb +1 -0
- data/lib/rex/ui/text/output/stdio.rb +0 -16
- data/lib/rex/ui/text/shell.rb +3 -0
- data/lib/rex/ui/text/table.rb +85 -19
- data/lib/rex/user_agent.rb +118 -0
- data/rex.gemspec +2 -2
- metadata +41 -14
- data/lib/rex/exploitation/powershell.rb +0 -62
- data/lib/rex/exploitation/powershell/parser.rb +0 -183
- data/lib/rex/payloads/meterpreter.rb +0 -2
- data/lib/rex/payloads/meterpreter/patch.rb +0 -136
@@ -295,6 +295,7 @@ class Client
|
|
295
295
|
end
|
296
296
|
sent_data = 0
|
297
297
|
sent_blocks = 0
|
298
|
+
send_retries = 0
|
298
299
|
expected_blocks = data_blocks.size
|
299
300
|
expected_size = data_blocks.join.size
|
300
301
|
if block_given?
|
@@ -302,24 +303,43 @@ class Client
|
|
302
303
|
yield "Sending #{expected_size} bytes (#{expected_blocks} blocks)"
|
303
304
|
end
|
304
305
|
data_blocks.each_with_index do |data_block,idx|
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
306
|
+
loop do
|
307
|
+
req = [OpData, (idx + 1), data_block].pack("nnA*")
|
308
|
+
if self.server_sock.sendto(req, host, port) <= 0
|
309
|
+
send_retries += 1
|
310
|
+
if send_retries > 100
|
311
|
+
break
|
312
|
+
else
|
313
|
+
next
|
314
|
+
end
|
315
|
+
end
|
316
|
+
send_retries = 0
|
317
|
+
res = self.server_sock.recvfrom(65535)
|
318
|
+
if res
|
319
|
+
code, type, msg = parse_tftp_response(res[0])
|
320
|
+
if code == 4
|
321
|
+
if type == idx + 1
|
322
|
+
sent_blocks += 1
|
323
|
+
sent_data += data_block.size
|
324
|
+
yield "Sent #{data_block.size} bytes in block #{idx+1}" if block_given?
|
325
|
+
break
|
326
|
+
else
|
327
|
+
next
|
328
|
+
end
|
329
|
+
else
|
330
|
+
if block_given?
|
331
|
+
yield "Got an unexpected response: Code:%d, Type:%d, Message:'%s'. Aborting." % [code, type, msg]
|
332
|
+
end
|
333
|
+
break
|
318
334
|
end
|
319
|
-
break
|
320
335
|
end
|
321
336
|
end
|
322
337
|
end
|
338
|
+
|
339
|
+
if send_retries > 100
|
340
|
+
yield "Too many send retries, aborted"
|
341
|
+
end
|
342
|
+
|
323
343
|
if block_given?
|
324
344
|
if(sent_data == expected_size)
|
325
345
|
yield("Transferred #{sent_data} bytes in #{sent_blocks} blocks, upload complete!")
|
@@ -327,6 +347,7 @@ class Client
|
|
327
347
|
yield "Upload complete, but with errors."
|
328
348
|
end
|
329
349
|
end
|
350
|
+
|
330
351
|
if sent_data == expected_size
|
331
352
|
self.status = {:success => [
|
332
353
|
self.local_file,
|
data/lib/rex/ropbuilder.rb
CHANGED
@@ -56,6 +56,7 @@ class Rex::Socket::Parameters
|
|
56
56
|
# @option hash [Bool] 'Bool' Create a bare socket
|
57
57
|
# @option hash [Bool] 'Server' Whether or not this should be a server
|
58
58
|
# @option hash [Bool] 'SSL' Whether or not SSL should be used
|
59
|
+
# @option hash [OpenSSL::SSL::SSLContext] 'SSLContext' Use a pregenerated SSL Context
|
59
60
|
# @option hash [String] 'SSLVersion' Specify Auto, SSL2, SSL3, or TLS1 (Auto is
|
60
61
|
# default)
|
61
62
|
# @option hash [String] 'SSLCert' A file containing an SSL certificate (for
|
@@ -117,6 +118,10 @@ class Rex::Socket::Parameters
|
|
117
118
|
self.ssl = false
|
118
119
|
end
|
119
120
|
|
121
|
+
if hash['SSLContext']
|
122
|
+
self.sslctx = hash['SSLContext']
|
123
|
+
end
|
124
|
+
|
120
125
|
supported_ssl_versions = ['Auto', 'SSL2', 'SSL23', 'TLS1', 'SSL3', :Auto, :SSLv2, :SSLv3, :SSLv23, :TLSv1]
|
121
126
|
if (hash['SSLVersion'] and supported_ssl_versions.include? hash['SSLVersion'])
|
122
127
|
self.ssl_version = hash['SSLVersion']
|
@@ -324,6 +329,10 @@ class Rex::Socket::Parameters
|
|
324
329
|
# @return [Bool]
|
325
330
|
attr_accessor :ssl
|
326
331
|
|
332
|
+
# Pre configured SSL Context to use
|
333
|
+
# @return [OpenSSL::SSL::SSLContext]
|
334
|
+
attr_accessor :sslctx
|
335
|
+
|
327
336
|
# What version of SSL to use (Auto, SSL2, SSL3, SSL23, TLS1)
|
328
337
|
# @return [String,Symbol]
|
329
338
|
attr_accessor :ssl_version
|
data/lib/rex/socket/ssl_tcp.rb
CHANGED
@@ -56,52 +56,39 @@ begin
|
|
56
56
|
def initsock(params = nil)
|
57
57
|
super
|
58
58
|
|
59
|
-
#
|
60
|
-
|
59
|
+
# Default to SSLv23 (automatically negotiate)
|
60
|
+
version = :SSLv23
|
61
61
|
|
62
|
-
#
|
62
|
+
# Let the caller specify a particular SSL/TLS version
|
63
63
|
if params
|
64
64
|
case params.ssl_version
|
65
65
|
when 'SSL2', :SSLv2
|
66
|
-
|
67
|
-
|
68
|
-
|
66
|
+
version = :SSLv2
|
67
|
+
# 'TLS' will be the new name for autonegotation with newer versions of OpenSSL
|
68
|
+
when 'SSL23', :SSLv23, 'TLS'
|
69
|
+
version = :SSLv23
|
69
70
|
when 'SSL3', :SSLv3
|
70
|
-
|
71
|
-
when 'TLS1', :TLSv1
|
72
|
-
|
73
|
-
|
74
|
-
|
71
|
+
version = :SSLv3
|
72
|
+
when 'TLS1','TLS1.0', :TLSv1
|
73
|
+
version = :TLSv1
|
74
|
+
when 'TLS1.1', :TLSv1_1
|
75
|
+
version = :TLSv1_1
|
76
|
+
when 'TLS1.2', :TLSv1_2
|
77
|
+
version = :TLSv1_2
|
75
78
|
end
|
76
79
|
end
|
77
80
|
|
78
|
-
# Limit our versions to those supported by the linked OpenSSL library
|
79
|
-
versions = versions.select {|v| OpenSSL::SSL::SSLContext::METHODS.include? v }
|
80
|
-
|
81
81
|
# Raise an error if no selected versions are supported
|
82
|
-
if
|
82
|
+
if ! OpenSSL::SSL::SSLContext::METHODS.include? version
|
83
83
|
raise ArgumentError, 'The system OpenSSL does not support the requested SSL/TLS version'
|
84
84
|
end
|
85
85
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
versions.each do |version|
|
90
|
-
begin
|
91
|
-
# Try intializing the socket with this SSL/TLS version
|
92
|
-
# This will throw an exception if it fails
|
93
|
-
initsock_with_ssl_version(params, version)
|
94
|
-
|
95
|
-
# Success! Record what method was used and return
|
96
|
-
self.ssl_negotiated_version = version
|
97
|
-
return
|
98
|
-
rescue OpenSSL::SSL::SSLError => e
|
99
|
-
last_error = e
|
100
|
-
end
|
101
|
-
end
|
86
|
+
# Try intializing the socket with this SSL/TLS version
|
87
|
+
# This will throw an exception if it fails
|
88
|
+
initsock_with_ssl_version(params, version)
|
102
89
|
|
103
|
-
#
|
104
|
-
|
90
|
+
# Track the SSL version
|
91
|
+
self.ssl_negotiated_version = version
|
105
92
|
end
|
106
93
|
|
107
94
|
def initsock_with_ssl_version(params, version)
|
@@ -137,9 +124,6 @@ begin
|
|
137
124
|
# Tie the context to a socket
|
138
125
|
self.sslsock = OpenSSL::SSL::SSLSocket.new(self, self.sslctx)
|
139
126
|
|
140
|
-
# XXX - enabling this causes infinite recursion, so disable for now
|
141
|
-
# self.sslsock.sync_close = true
|
142
|
-
|
143
127
|
# Force a negotiation timeout
|
144
128
|
begin
|
145
129
|
Timeout.timeout(params.timeout) do
|
@@ -366,7 +350,11 @@ begin
|
|
366
350
|
|
367
351
|
attr_reader :peer_verified # :nodoc:
|
368
352
|
attr_reader :ssl_negotiated_version # :nodoc:
|
369
|
-
attr_accessor :sslsock, :sslctx # :nodoc:
|
353
|
+
attr_accessor :sslsock, :sslctx, :sslhash # :nodoc:
|
354
|
+
|
355
|
+
def type?
|
356
|
+
return 'tcp-ssl'
|
357
|
+
end
|
370
358
|
|
371
359
|
protected
|
372
360
|
|
@@ -377,9 +365,5 @@ protected
|
|
377
365
|
rescue LoadError
|
378
366
|
end
|
379
367
|
|
380
|
-
def type?
|
381
|
-
return 'tcp-ssl'
|
382
|
-
end
|
383
|
-
|
384
368
|
end
|
385
369
|
|
@@ -2,6 +2,7 @@
|
|
2
2
|
require 'rex/socket'
|
3
3
|
require 'rex/socket/tcp_server'
|
4
4
|
require 'rex/io/stream_server'
|
5
|
+
require 'rex/parser/x509_certificate'
|
5
6
|
|
6
7
|
###
|
7
8
|
#
|
@@ -47,8 +48,14 @@ module Rex::Socket::SslTcpServer
|
|
47
48
|
end
|
48
49
|
|
49
50
|
def initsock(params = nil)
|
50
|
-
raise RuntimeError,
|
51
|
-
|
51
|
+
raise RuntimeError, 'No OpenSSL support' unless @@loaded_openssl
|
52
|
+
|
53
|
+
if params && params.sslctx && params.sslctx.kind_of?(OpenSSL::SSL::SSLContext)
|
54
|
+
self.sslctx = params.sslctx
|
55
|
+
else
|
56
|
+
self.sslctx = makessl(params)
|
57
|
+
end
|
58
|
+
|
52
59
|
super
|
53
60
|
end
|
54
61
|
|
@@ -108,25 +115,7 @@ module Rex::Socket::SslTcpServer
|
|
108
115
|
# @param [String] ssl_cert
|
109
116
|
# @return [String, String, Array]
|
110
117
|
def self.ssl_parse_pem(ssl_cert)
|
111
|
-
|
112
|
-
key = nil
|
113
|
-
chain = nil
|
114
|
-
|
115
|
-
certs = []
|
116
|
-
ssl_cert.scan(/-----BEGIN\s*[^\-]+-----+\r?\n[^\-]*-----END\s*[^\-]+-----\r?\n?/nm).each do |pem|
|
117
|
-
if pem =~ /PRIVATE KEY/
|
118
|
-
key = OpenSSL::PKey::RSA.new(pem)
|
119
|
-
elsif pem =~ /CERTIFICATE/
|
120
|
-
certs << OpenSSL::X509::Certificate.new(pem)
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
cert = certs.shift
|
125
|
-
if certs.length > 0
|
126
|
-
chain = certs
|
127
|
-
end
|
128
|
-
|
129
|
-
[key, cert, chain]
|
118
|
+
Rex::Parser::X509Certificate.parse_pem(ssl_cert)
|
130
119
|
end
|
131
120
|
|
132
121
|
#
|
data/lib/rex/sslscan/result.rb
CHANGED
@@ -15,6 +15,24 @@ class Result
|
|
15
15
|
@cert = nil
|
16
16
|
@ciphers = Set.new
|
17
17
|
@supported_versions = [:SSLv2, :SSLv3, :TLSv1]
|
18
|
+
@deprecated_weak_ciphers = [
|
19
|
+
'ECDHE-RSA-DES-CBC3-SHA',
|
20
|
+
'ECDHE-ECDSA-DES-CBC3-SHA',
|
21
|
+
'SRP-DSS-3DES-EDE-CBC-SHA',
|
22
|
+
'SRP-RSA-3DES-EDE-CBC-SHA',
|
23
|
+
'SRP-3DES-EDE-CBC-SHA',
|
24
|
+
'EDH-RSA-DES-CBC3-SHA',
|
25
|
+
'EDH-DSS-DES-CBC3-SHA',
|
26
|
+
'ECDH-RSA-DES-CBC3-SHA',
|
27
|
+
'ECDH-ECDSA-DES-CBC3-SHA',
|
28
|
+
'DES-CBC3-SHA',
|
29
|
+
'PSK-3DES-EDE-CBC-SHA',
|
30
|
+
'EXP-EDH-RSA-DES-CBC-SHA',
|
31
|
+
'EXP-EDH-DSS-DES-CBC-SHA',
|
32
|
+
'EXP-DES-CBC-SHA',
|
33
|
+
'EXP-RC2-CBC-MD5',
|
34
|
+
'EXP-RC4-MD5'
|
35
|
+
]
|
18
36
|
end
|
19
37
|
|
20
38
|
def cert
|
@@ -113,7 +131,8 @@ class Result
|
|
113
131
|
unless @supported_versions.include? version
|
114
132
|
raise ArgumentError, "Must be a supported SSL Version"
|
115
133
|
end
|
116
|
-
unless OpenSSL::SSL::SSLContext.new(version).ciphers.flatten.include?
|
134
|
+
unless OpenSSL::SSL::SSLContext.new(version).ciphers.flatten.include?(cipher) \
|
135
|
+
|| @deprecated_weak_ciphers.include?(cipher)
|
117
136
|
raise ArgumentError, "Must be a valid SSL Cipher for #{version}!"
|
118
137
|
end
|
119
138
|
unless key_length.kind_of? Fixnum
|
data/lib/rex/text.rb
CHANGED
@@ -3,18 +3,8 @@ require 'digest/md5'
|
|
3
3
|
require 'digest/sha1'
|
4
4
|
require 'stringio'
|
5
5
|
require 'cgi'
|
6
|
-
require 'rex/
|
7
|
-
|
8
|
-
%W{ iconv zlib }.each do |libname|
|
9
|
-
begin
|
10
|
-
old_verbose = $VERBOSE
|
11
|
-
$VERBOSE = nil
|
12
|
-
require libname
|
13
|
-
rescue ::LoadError
|
14
|
-
ensure
|
15
|
-
$VERBOSE = old_verbose
|
16
|
-
end
|
17
|
-
end
|
6
|
+
require 'rex/powershell'
|
7
|
+
require 'zlib'
|
18
8
|
|
19
9
|
module Rex
|
20
10
|
|
@@ -42,8 +32,10 @@ module Text
|
|
42
32
|
UpperAlpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
43
33
|
LowerAlpha = "abcdefghijklmnopqrstuvwxyz"
|
44
34
|
Numerals = "0123456789"
|
45
|
-
Base32
|
46
|
-
|
35
|
+
Base32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
|
36
|
+
Base64 = UpperAlpha + LowerAlpha + Numerals + '+/'
|
37
|
+
Base64Url = UpperAlpha + LowerAlpha + Numerals + '-_'
|
38
|
+
Alpha = UpperAlpha + LowerAlpha
|
47
39
|
AlphaNumeric = Alpha + Numerals
|
48
40
|
HighAscii = [*(0x80 .. 0xff)].pack("C*")
|
49
41
|
LowAscii = [*(0x00 .. 0x1f)].pack("C*")
|
@@ -53,7 +45,95 @@ module Text
|
|
53
45
|
|
54
46
|
DefaultPatternSets = [ Rex::Text::UpperAlpha, Rex::Text::LowerAlpha, Rex::Text::Numerals ]
|
55
47
|
|
56
|
-
#
|
48
|
+
# The Iconv translation table for IBM's mainframe / System Z
|
49
|
+
# (z/os, s390, mvs, etc) - This is a different implementation
|
50
|
+
# of EBCDIC than the Iconv_EBCDIC below.
|
51
|
+
# It is technically referred to as Code Page IBM1047.
|
52
|
+
# This will be net new (until Ruby supports 1047 code page)
|
53
|
+
# for all Mainframe / SystemZ based modules
|
54
|
+
# that need to convert ASCII to EBCDIC
|
55
|
+
#
|
56
|
+
# The bytes are indexed by ASCII conversion number
|
57
|
+
# e.g. Iconv_IBM1047[0x41] == \xc1 for letter "A"
|
58
|
+
#
|
59
|
+
# Note the characters CANNOT be assumed to be in any logical
|
60
|
+
# order. Nor are the tables reversible. Lookups must be for each byte
|
61
|
+
# https://gist.github.com/bigendiansmalls/b08483ecedff52cc8fa3
|
62
|
+
#
|
63
|
+
Iconv_IBM1047 = [
|
64
|
+
"\x00","\x01","\x02","\x03","\x37","\x2d","\x2e","\x2f",
|
65
|
+
"\x16","\x05","\x15","\x0b","\x0c","\x0d","\x0e","\x0f","\x10",
|
66
|
+
"\x11","\x12","\x13","\x3c","\x3d","\x32","\x26","\x18","\x19",
|
67
|
+
"\x3f","\x27","\x1c","\x1d","\x1e","\x1f","\x40","\x5a","\x7f",
|
68
|
+
"\x7b","\x5b","\x6c","\x50","\x7d","\x4d","\x5d","\x5c","\x4e",
|
69
|
+
"\x6b","\x60","\x4b","\x61","\xf0","\xf1","\xf2","\xf3","\xf4",
|
70
|
+
"\xf5","\xf6","\xf7","\xf8","\xf9","\x7a","\x5e","\x4c","\x7e",
|
71
|
+
"\x6e","\x6f","\x7c","\xc1","\xc2","\xc3","\xc4","\xc5","\xc6",
|
72
|
+
"\xc7","\xc8","\xc9","\xd1","\xd2","\xd3","\xd4","\xd5","\xd6",
|
73
|
+
"\xd7","\xd8","\xd9","\xe2","\xe3","\xe4","\xe5","\xe6","\xe7",
|
74
|
+
"\xe8","\xe9","\xad","\xe0","\xbd","\x5f","\x6d","\x79","\x81",
|
75
|
+
"\x82","\x83","\x84","\x85","\x86","\x87","\x88","\x89","\x91",
|
76
|
+
"\x92","\x93","\x94","\x95","\x96","\x97","\x98","\x99","\xa2",
|
77
|
+
"\xa3","\xa4","\xa5","\xa6","\xa7","\xa8","\xa9","\xc0","\x4f",
|
78
|
+
"\xd0","\xa1","\x07","\x20","\x21","\x22","\x23","\x24","\x25",
|
79
|
+
"\x06","\x17","\x28","\x29","\x2a","\x2b","\x2c","\x09","\x0a",
|
80
|
+
"\x1b","\x30","\x31","\x1a","\x33","\x34","\x35","\x36","\x08",
|
81
|
+
"\x38","\x39","\x3a","\x3b","\x04","\x14","\x3e","\xff","\x41",
|
82
|
+
"\xaa","\x4a","\xb1","\x9f","\xb2","\x6a","\xb5","\xbb","\xb4",
|
83
|
+
"\x9a","\x8a","\xb0","\xca","\xaf","\xbc","\x90","\x8f","\xea",
|
84
|
+
"\xfa","\xbe","\xa0","\xb6","\xb3","\x9d","\xda","\x9b","\x8b",
|
85
|
+
"\xb7","\xb8","\xb9","\xab","\x64","\x65","\x62","\x66","\x63",
|
86
|
+
"\x67","\x9e","\x68","\x74","\x71","\x72","\x73","\x78","\x75",
|
87
|
+
"\x76","\x77","\xac","\x69","\xed","\xee","\xeb","\xef","\xec",
|
88
|
+
"\xbf","\x80","\xfd","\xfe","\xfb","\xfc","\xba","\xae","\x59",
|
89
|
+
"\x44","\x45","\x42","\x46","\x43","\x47","\x9c","\x48","\x54",
|
90
|
+
"\x51","\x52","\x53","\x58","\x55","\x56","\x57","\x8c","\x49",
|
91
|
+
"\xcd","\xce","\xcb","\xcf","\xcc","\xe1","\x70","\xdd","\xde",
|
92
|
+
"\xdb","\xdc","\x8d","\x8e","\xdf"
|
93
|
+
]
|
94
|
+
|
95
|
+
#
|
96
|
+
# This is the reverse of the above, converts EBCDIC -> ASCII
|
97
|
+
# The bytes are indexed by IBM1047(EBCDIC) conversion number
|
98
|
+
# e.g. Iconv_ISO8859_1[0xc1] = \x41 for letter "A"
|
99
|
+
#
|
100
|
+
# Note the characters CANNOT be assumed to be in any logical (e.g. sequential)
|
101
|
+
# order. Nor are the tables reversible. Lookups must be done byte by byte
|
102
|
+
#
|
103
|
+
Iconv_ISO8859_1 = [
|
104
|
+
"\x00","\x01","\x02","\x03","\x9c","\x09","\x86","\x7f",
|
105
|
+
"\x97","\x8d","\x8e","\x0b","\x0c","\x0d","\x0e","\x0f","\x10",
|
106
|
+
"\x11","\x12","\x13","\x9d","\x0a","\x08","\x87","\x18","\x19",
|
107
|
+
"\x92","\x8f","\x1c","\x1d","\x1e","\x1f","\x80","\x81","\x82",
|
108
|
+
"\x83","\x84","\x85","\x17","\x1b","\x88","\x89","\x8a","\x8b",
|
109
|
+
"\x8c","\x05","\x06","\x07","\x90","\x91","\x16","\x93","\x94",
|
110
|
+
"\x95","\x96","\x04","\x98","\x99","\x9a","\x9b","\x14","\x15",
|
111
|
+
"\x9e","\x1a","\x20","\xa0","\xe2","\xe4","\xe0","\xe1","\xe3",
|
112
|
+
"\xe5","\xe7","\xf1","\xa2","\x2e","\x3c","\x28","\x2b","\x7c",
|
113
|
+
"\x26","\xe9","\xea","\xeb","\xe8","\xed","\xee","\xef","\xec",
|
114
|
+
"\xdf","\x21","\x24","\x2a","\x29","\x3b","\x5e","\x2d","\x2f",
|
115
|
+
"\xc2","\xc4","\xc0","\xc1","\xc3","\xc5","\xc7","\xd1","\xa6",
|
116
|
+
"\x2c","\x25","\x5f","\x3e","\x3f","\xf8","\xc9","\xca","\xcb",
|
117
|
+
"\xc8","\xcd","\xce","\xcf","\xcc","\x60","\x3a","\x23","\x40",
|
118
|
+
"\x27","\x3d","\x22","\xd8","\x61","\x62","\x63","\x64","\x65",
|
119
|
+
"\x66","\x67","\x68","\x69","\xab","\xbb","\xf0","\xfd","\xfe",
|
120
|
+
"\xb1","\xb0","\x6a","\x6b","\x6c","\x6d","\x6e","\x6f","\x70",
|
121
|
+
"\x71","\x72","\xaa","\xba","\xe6","\xb8","\xc6","\xa4","\xb5",
|
122
|
+
"\x7e","\x73","\x74","\x75","\x76","\x77","\x78","\x79","\x7a",
|
123
|
+
"\xa1","\xbf","\xd0","\x5b","\xde","\xae","\xac","\xa3","\xa5",
|
124
|
+
"\xb7","\xa9","\xa7","\xb6","\xbc","\xbd","\xbe","\xdd","\xa8",
|
125
|
+
"\xaf","\x5d","\xb4","\xd7","\x7b","\x41","\x42","\x43","\x44",
|
126
|
+
"\x45","\x46","\x47","\x48","\x49","\xad","\xf4","\xf6","\xf2",
|
127
|
+
"\xf3","\xf5","\x7d","\x4a","\x4b","\x4c","\x4d","\x4e","\x4f",
|
128
|
+
"\x50","\x51","\x52","\xb9","\xfb","\xfc","\xf9","\xfa","\xff",
|
129
|
+
"\x5c","\xf7","\x53","\x54","\x55","\x56","\x57","\x58","\x59",
|
130
|
+
"\x5a","\xb2","\xd4","\xd6","\xd2","\xd3","\xd5","\x30","\x31",
|
131
|
+
"\x32","\x33","\x34","\x35","\x36","\x37","\x38","\x39","\xb3",
|
132
|
+
"\xdb","\xdc","\xd9","\xda","\x9f"
|
133
|
+
]
|
134
|
+
|
135
|
+
# The Iconv translation table. The Iconv gem is deprecated in favor of
|
136
|
+
# String#encode, yet there is no encoding for EBCDIC. See #4525
|
57
137
|
Iconv_EBCDIC = [
|
58
138
|
"\x00", "\x01", "\x02", "\x03", "7", "-", ".", "/", "\x16", "\x05",
|
59
139
|
"%", "\v", "\f", "\r", "\x0E", "\x0F", "\x10", "\x11", "\x12", "\x13",
|
@@ -306,7 +386,7 @@ module Text
|
|
306
386
|
# Converts a raw string to a powershell byte array
|
307
387
|
#
|
308
388
|
def self.to_powershell(str, name = "buf")
|
309
|
-
return Rex::
|
389
|
+
return Rex::Powershell::Script.to_byte_array(str, name)
|
310
390
|
end
|
311
391
|
|
312
392
|
#
|
@@ -372,31 +452,26 @@ module Text
|
|
372
452
|
return str
|
373
453
|
end
|
374
454
|
|
455
|
+
# Converts US-ASCII to UTF-8, skipping over any characters which don't
|
456
|
+
# convert cleanly. This is a convenience method that wraps
|
457
|
+
# String#encode with non-raising default paramaters.
|
375
458
|
#
|
376
|
-
#
|
377
|
-
#
|
459
|
+
# @param str [String] An encodable ASCII string
|
460
|
+
# @return [String] a UTF-8 equivalent
|
461
|
+
# @note This method will discard invalid characters
|
378
462
|
def self.to_utf8(str)
|
379
|
-
|
380
|
-
if str.respond_to?(:encode)
|
381
|
-
# Skip over any bytes that fail to convert to UTF-8
|
382
|
-
return str.encode('utf-8', { :invalid => :replace, :undef => :replace, :replace => '' })
|
383
|
-
end
|
384
|
-
|
385
|
-
begin
|
386
|
-
Iconv.iconv("utf-8","iso-8859-1", str).join(" ")
|
387
|
-
rescue
|
388
|
-
raise ::RuntimeError, "Your installation does not support iconv (needed for utf8 conversion)"
|
389
|
-
end
|
463
|
+
str.encode('utf-8', { :invalid => :replace, :undef => :replace, :replace => '' })
|
390
464
|
end
|
391
465
|
|
392
|
-
#
|
393
|
-
# Converts ASCII to EBCDIC
|
394
|
-
#
|
395
466
|
class IllegalSequence < ArgumentError; end
|
396
467
|
|
397
|
-
# A native implementation of the ASCII
|
398
|
-
#
|
399
|
-
|
468
|
+
# A native implementation of the ASCII to EBCDIC conversion table, since
|
469
|
+
# EBCDIC isn't available to String#encode as of Ruby 2.1
|
470
|
+
#
|
471
|
+
# @param str [String] An encodable ASCII string
|
472
|
+
# @return [String] an EBCDIC encoded string
|
473
|
+
# @note This method will raise in the event of invalid characters
|
474
|
+
def self.to_ebcdic(str)
|
400
475
|
new_str = []
|
401
476
|
str.each_byte do |x|
|
402
477
|
if Iconv_ASCII.index(x.chr)
|
@@ -408,9 +483,13 @@ module Text
|
|
408
483
|
new_str.join
|
409
484
|
end
|
410
485
|
|
411
|
-
# A native implementation of the EBCDIC
|
412
|
-
#
|
413
|
-
|
486
|
+
# A native implementation of the EBCDIC to ASCII conversion table, since
|
487
|
+
# EBCDIC isn't available to String#encode as of Ruby 2.1
|
488
|
+
#
|
489
|
+
# @param str [String] an EBCDIC encoded string
|
490
|
+
# @return [String] An encodable ASCII string
|
491
|
+
# @note This method will raise in the event of invalid characters
|
492
|
+
def self.from_ebcdic(str)
|
414
493
|
new_str = []
|
415
494
|
str.each_byte do |x|
|
416
495
|
if Iconv_EBCDIC.index(x.chr)
|
@@ -422,27 +501,37 @@ module Text
|
|
422
501
|
new_str.join
|
423
502
|
end
|
424
503
|
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
504
|
+
#
|
505
|
+
# The next two are the same as the above, except strictly for z/os
|
506
|
+
# conversions
|
507
|
+
# strictly for IBM1047 -> ISO8859-1
|
508
|
+
# A native implementation of the IBM1047(EBCDIC) -> ISO8859-1(ASCII)
|
509
|
+
# conversion table, since EBCDIC isn't available to String#encode as of Ruby 2.1
|
510
|
+
# all 256 bytes are defined
|
511
|
+
#
|
512
|
+
def self.to_ibm1047(str)
|
513
|
+
return str if str.nil?
|
514
|
+
new_str = []
|
515
|
+
str.each_byte do |x|
|
516
|
+
new_str << Iconv_IBM1047[x.ord]
|
432
517
|
end
|
518
|
+
new_str.join
|
433
519
|
end
|
434
520
|
|
435
521
|
#
|
436
|
-
#
|
522
|
+
# The next two are the same as the above, except strictly for z/os
|
523
|
+
# conversions
|
524
|
+
# strictly for ISO8859-1 -> IBM1047
|
525
|
+
# A native implementation of the ISO8859-1(ASCII) -> IBM1047(EBCDIC)
|
526
|
+
# conversion table, since EBCDIC isn't available to String#encode as of Ruby 2.1
|
437
527
|
#
|
438
|
-
def self.
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
rescue
|
444
|
-
self.from_ebcdic_rex(str)
|
528
|
+
def self.from_ibm1047(str)
|
529
|
+
return str if str.nil?
|
530
|
+
new_str = []
|
531
|
+
str.each_byte do |x|
|
532
|
+
new_str << Iconv_ISO8859_1[x.ord]
|
445
533
|
end
|
534
|
+
new_str.join
|
446
535
|
end
|
447
536
|
|
448
537
|
#
|
@@ -1037,6 +1126,56 @@ module Text
|
|
1037
1126
|
return output
|
1038
1127
|
end
|
1039
1128
|
|
1129
|
+
#
|
1130
|
+
# Converts a string to one similar to what would be used by cowsay(1), a UNIX utility for
|
1131
|
+
# displaying text as if it was coming from an ASCII-cow's mouth:
|
1132
|
+
#
|
1133
|
+
# __________________
|
1134
|
+
# < the cow says moo >
|
1135
|
+
# ------------------
|
1136
|
+
# \ ^__^
|
1137
|
+
# \ (oo)\_______
|
1138
|
+
# (__)\ )\/\
|
1139
|
+
# ||----w |
|
1140
|
+
# || ||
|
1141
|
+
#
|
1142
|
+
# @param text [String] The string to cowsay
|
1143
|
+
# @param width [Fixnum] Width of the cow's cloud. Default's to cowsay(1)'s default, 39.
|
1144
|
+
def self.cowsay(text, width=39)
|
1145
|
+
# cowsay(1) chunks a message up into 39-byte chunks and wraps it in '| ' and ' |'
|
1146
|
+
# Rex::Text.wordwrap(text, 0, 39, ' |', '| ') almost does this, but won't
|
1147
|
+
# split a word that has > 39 characters in it which results in oddly formed
|
1148
|
+
# text in the cowsay banner, so just do it by hand. This big mess wraps
|
1149
|
+
# the provided text in an ASCII-cloud and then makes it look like the cloud
|
1150
|
+
# is a thought/word coming from the ASCII-cow. Each line in the
|
1151
|
+
# ASCII-cloud is no more than the specified number-characters long, and the
|
1152
|
+
# cloud corners are made to look rounded
|
1153
|
+
text_lines = text.scan(Regexp.new(".{1,#{width-4}}"))
|
1154
|
+
max_length = text_lines.map(&:size).sort.last
|
1155
|
+
cloud_parts = []
|
1156
|
+
cloud_parts << " #{'_' * (max_length + 2)}"
|
1157
|
+
if text_lines.size == 1
|
1158
|
+
cloud_parts << "< #{text} >"
|
1159
|
+
else
|
1160
|
+
cloud_parts << "/ #{text_lines.first.ljust(max_length, ' ')} \\"
|
1161
|
+
if text_lines.size > 2
|
1162
|
+
text_lines[1, text_lines.length - 2].each do |line|
|
1163
|
+
cloud_parts << "| #{line.ljust(max_length, ' ')} |"
|
1164
|
+
end
|
1165
|
+
end
|
1166
|
+
cloud_parts << "\\ #{text_lines.last.ljust(max_length, ' ')} /"
|
1167
|
+
end
|
1168
|
+
cloud_parts << " #{'-' * (max_length + 2)}"
|
1169
|
+
cloud_parts << <<EOS
|
1170
|
+
\\ ,__,
|
1171
|
+
\\ (oo)____
|
1172
|
+
(__) )\\
|
1173
|
+
||--|| *
|
1174
|
+
EOS
|
1175
|
+
cloud_parts.join("\n")
|
1176
|
+
end
|
1177
|
+
|
1178
|
+
|
1040
1179
|
##
|
1041
1180
|
#
|
1042
1181
|
# Transforms
|
@@ -1134,6 +1273,24 @@ module Text
|
|
1134
1273
|
str.to_s.unpack("m")[0]
|
1135
1274
|
end
|
1136
1275
|
|
1276
|
+
#
|
1277
|
+
# Base64 encoder (URL-safe RFC6920)
|
1278
|
+
#
|
1279
|
+
def self.encode_base64url(str, delim='')
|
1280
|
+
encode_base64(str, delim).
|
1281
|
+
tr('+/', '-_').
|
1282
|
+
gsub('=', '')
|
1283
|
+
end
|
1284
|
+
|
1285
|
+
#
|
1286
|
+
# Base64 decoder (URL-safe RFC6920, ignores invalid characters)
|
1287
|
+
#
|
1288
|
+
def self.decode_base64url(str)
|
1289
|
+
decode_base64(
|
1290
|
+
str.gsub(/[^a-zA-Z0-9_\-]/, '').
|
1291
|
+
tr('-_', '+/'))
|
1292
|
+
end
|
1293
|
+
|
1137
1294
|
#
|
1138
1295
|
# Raw MD5 digest of the supplied string
|
1139
1296
|
#
|
@@ -1274,6 +1431,18 @@ module Text
|
|
1274
1431
|
rand_base(len, bad, *foo )
|
1275
1432
|
end
|
1276
1433
|
|
1434
|
+
# Generate random bytes of base64 data
|
1435
|
+
def self.rand_text_base64(len, bad='')
|
1436
|
+
foo = Base64.unpack('C*').map{ |c| c.chr }
|
1437
|
+
rand_base(len, bad, *foo )
|
1438
|
+
end
|
1439
|
+
|
1440
|
+
# Generate random bytes of base64url data
|
1441
|
+
def self.rand_text_base64url(len, bad='')
|
1442
|
+
foo = Base64Url.unpack('C*').map{ |c| c.chr }
|
1443
|
+
rand_base(len, bad, *foo )
|
1444
|
+
end
|
1445
|
+
|
1277
1446
|
# Generate a random GUID
|
1278
1447
|
#
|
1279
1448
|
# @example
|
@@ -1523,7 +1692,10 @@ module Text
|
|
1523
1692
|
# @param data [#delete]
|
1524
1693
|
# @param badchars [String] A list of characters considered to be bad
|
1525
1694
|
def self.remove_badchars(data, badchars = '')
|
1526
|
-
data.
|
1695
|
+
return data if badchars.length == 0
|
1696
|
+
badchars_pat = badchars.unpack("C*").map{|c| "\\x%.2x" % c}.join
|
1697
|
+
data.gsub!(/[#{badchars_pat}]/n, '')
|
1698
|
+
data
|
1527
1699
|
end
|
1528
1700
|
|
1529
1701
|
#
|
@@ -1532,7 +1704,8 @@ module Text
|
|
1532
1704
|
# @param keepers [String]
|
1533
1705
|
# @return [String] All characters not contained in +keepers+
|
1534
1706
|
def self.charset_exclude(keepers)
|
1535
|
-
[*(0..255)].
|
1707
|
+
excluded_bytes = [*(0..255)] - keepers.unpack("C*")
|
1708
|
+
excluded_bytes.pack("C*")
|
1536
1709
|
end
|
1537
1710
|
|
1538
1711
|
#
|
@@ -1643,6 +1816,19 @@ module Text
|
|
1643
1816
|
mail_address << Rex::Text.rand_hostname
|
1644
1817
|
end
|
1645
1818
|
|
1819
|
+
#
|
1820
|
+
# Calculate the block API hash for the given module/function
|
1821
|
+
#
|
1822
|
+
# @param mod [String] The name of the module containing the target function.
|
1823
|
+
# @param fun [String] The name of the function.
|
1824
|
+
#
|
1825
|
+
# @return [String] The hash of the mod/fun pair in string format
|
1826
|
+
def self.block_api_hash(mod, fun)
|
1827
|
+
unicode_mod = (mod.upcase + "\x00").unpack('C*').pack('v*')
|
1828
|
+
mod_hash = self.ror13_hash(unicode_mod)
|
1829
|
+
fun_hash = self.ror13_hash(fun + "\x00")
|
1830
|
+
"0x#{(mod_hash + fun_hash & 0xFFFFFFFF).to_s(16)}"
|
1831
|
+
end
|
1646
1832
|
|
1647
1833
|
#
|
1648
1834
|
# Calculate the ROR13 hash of a given string
|