diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index d075606b112bc..ddc5b10d1f227 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -44,7 +44,7 @@ jobs: /usr/bin/docker-compose build test: - runs-on: ubuntu-18.04 + runs-on: ${{ matrix.os }} timeout-minutes: 40 services: @@ -66,8 +66,15 @@ jobs: ruby: - 2.6 - 2.7 - - 3.0.3 - - 3.1.1 + - 3.0 + - 3.1 + os: + - ubuntu-18.04 + - ubuntu-22.04 + exclude: + - { os: ubuntu-22.04, ruby: 2.6 } + - { os: ubuntu-22.04, ruby: 2.7 } + - { os: ubuntu-22.04, ruby: 3.0 } test_cmd: - bundle exec rake rspec-rerun:spec SPEC_OPTS="--tag content" - bundle exec rake rspec-rerun:spec SPEC_OPTS="--tag ~content" diff --git a/Gemfile b/Gemfile index fa176c6565dee..835fae238fd42 100755 --- a/Gemfile +++ b/Gemfile @@ -3,6 +3,12 @@ source 'https://rubygems.org' # spec.add_runtime_dependency '', [] gemspec name: 'metasploit-framework' +# gem 'ruby_smb', github: 'adfoster-r7/ruby_smb', branch: 'run-ubuntu-22.04-in-test-matrix' +# gem 'hrr_rb_ssh', github: 'adfoster-r7/hrr_rb_ssh', branch: 'investigate-openssl3-support' +# gem 'openssl-ccm', github: 'adfoster-r7/openssl-ccm', branch: 'add-support-openssl-3' +# gem 'openssl-cmac', github: 'adfoster-r7/openssl-cmac', branch: 'add-support-for-openssl3' +# gem 'metasploit-credential', github: 'adfoster-r7/metasploit-credential', branch: 'add-support-for-openssl3' + # separate from test as simplecov is not run on travis-ci group :coverage do # code coverage for tests diff --git a/Gemfile.lock b/Gemfile.lock index ec184056d5bc1..53d791ef83963 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -234,7 +234,7 @@ GEM activemodel (~> 6.0) activesupport (~> 6.0) railties (~> 6.0) - metasploit-credential (5.0.7) + metasploit-credential (5.0.8) metasploit-concern metasploit-model metasploit_data_models (>= 5.0.0) @@ -287,8 +287,8 @@ GEM octokit (4.25.1) faraday (>= 1, < 3) sawyer (~> 0.9) - openssl-ccm (1.2.2) - openssl-cmac (2.0.1) + openssl-ccm (1.2.3) + openssl-cmac (2.0.2) openvas-omp (0.0.4) packetfu (1.1.13) pcaprub @@ -429,7 +429,7 @@ GEM ruby-progressbar (1.11.0) ruby-rc4 (0.1.5) ruby2_keywords (0.0.5) - ruby_smb (3.1.6) + ruby_smb (3.1.7) bindata openssl-ccm openssl-cmac @@ -519,4 +519,4 @@ DEPENDENCIES yard BUNDLED WITH - 2.1.4 + 2.2.22 diff --git a/config/openssl.conf b/config/openssl.conf new file mode 100644 index 0000000000000..adfa225f64aaf --- /dev/null +++ b/config/openssl.conf @@ -0,0 +1,14 @@ +openssl_conf = openssl_init + +[openssl_init] +providers = provider_sect + +[provider_sect] +default = default_sect +legacy = legacy_sect + +[default_sect] +activate = 1 + +[legacy_sect] +activate = 1 diff --git a/documentation/modules/auxiliary/scanner/ssl/openssl_heartbleed.md b/documentation/modules/auxiliary/scanner/ssl/openssl_heartbleed.md index daed30667c2dd..2f64b4da9b142 100644 --- a/documentation/modules/auxiliary/scanner/ssl/openssl_heartbleed.md +++ b/documentation/modules/auxiliary/scanner/ssl/openssl_heartbleed.md @@ -25,6 +25,35 @@ openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -node If you receive `gethostbyname failure` error in `openssl`, add the client (metasploit) IP and hostname to your hosts file. +### Using docker + +Using the environment created by [vulhub](https://github.com/vulhub/vulhub/tree/master/openssl/CVE-2014-0160) + +First create a new docker-compose file: + +``` +version: '2' +services: + nginx: + image: vulhub/openssl:1.0.1c-with-nginx + ports: + - "8080:80" + - "8443:443" +``` + +Then run `docker-compose up` and verify that the service is running with: + +``` +$ curl https://localhost:8443 -k + +404 Not Found + +

404 Not Found

+
nginx/1.11.13
+ + +``` + ## Verification Steps 1. Install a vulnerable OpenSSL, start the service diff --git a/lib/msf/core/exploit/remote/http/typo3/login.rb b/lib/msf/core/exploit/remote/http/typo3/login.rb index 80f3f415728bf..9e13d40786435 100644 --- a/lib/msf/core/exploit/remote/http/typo3/login.rb +++ b/lib/msf/core/exploit/remote/http/typo3/login.rb @@ -97,15 +97,28 @@ def typo3_admin_cookie_valid?(cookiestring) # @param password [String] The clear text password to encrypt # @return [String] the base64 encoded password with prefixed 'rsa:' def typo3_helper_login_rsa(e, n, password) - key = OpenSSL::PKey::RSA.new - exponent = OpenSSL::BN.new e.hex.to_s - modulus = OpenSSL::BN.new n.hex.to_s - if key.respond_to?(:set_key) - # Ruby 2.4+ - key.set_key(modulus, exponent, nil) + # OpenSSL 3.0+ + if OpenSSL::PKey.respond_to?(:generate_key) + exponent = OpenSSL::BN.new e.hex + modulus = OpenSSL::BN.new n.hex + asn1 = OpenSSL::ASN1::Sequence( + [ + OpenSSL::ASN1::Integer(modulus), + OpenSSL::ASN1::Integer(exponent), + ] + ) + key = OpenSSL::PKey::RSA.new(asn1.to_der) else - key.e = exponent - key.n = modulus + key = OpenSSL::PKey::RSA.new + exponent = OpenSSL::BN.new e.hex.to_s + modulus = OpenSSL::BN.new n.hex.to_s + if key.respond_to?(:set_key) + # Ruby 2.4+ + key.set_key(modulus, exponent, nil) + else + key.e = exponent + key.n = modulus + end end enc = key.public_encrypt(password) enc_b64 = Rex::Text.encode_base64(enc) diff --git a/lib/msf/core/exploit/remote/kerberos/client/as_request.rb b/lib/msf/core/exploit/remote/kerberos/client/as_request.rb index 342ea2c56ae75..c252dc8d8de86 100644 --- a/lib/msf/core/exploit/remote/kerberos/client/as_request.rb +++ b/lib/msf/core/exploit/remote/kerberos/client/as_request.rb @@ -44,7 +44,7 @@ def build_as_pa_time_stamp(opts = {}) time_stamp = opts[:time_stamp] || Time.now pausec = opts[:pausec] || 0 etype = opts[:etype] || Rex::Proto::Kerberos::Crypto::RC4_HMAC - key = opts[:key] || '' + key = opts[:key] || OpenSSL::Random.random_bytes(16) pa_time_stamp = Rex::Proto::Kerberos::Model::PreAuthEncTimeStamp.new( pa_time_stamp: time_stamp, diff --git a/lib/msf/core/modules/loader/base.rb b/lib/msf/core/modules/loader/base.rb index 5e0192b1f2c83..06c6685921058 100644 --- a/lib/msf/core/modules/loader/base.rb +++ b/lib/msf/core/modules/loader/base.rb @@ -183,6 +183,13 @@ def load_module(parent_path, type, module_reference_name, options={}) causal_message: 'invalid module filename (must be lowercase alphanumeric snake case)' )) return false + rescue => e + load_error(module_path, Msf::Modules::Error.new( + module_path: module_path, + module_reference_name: module_reference_name, + causal_message: "unknown error #{e.message}" + )) + return false end diff --git a/lib/msf/util/windows_crypto_helpers.rb b/lib/msf/util/windows_crypto_helpers.rb index a5e6afb033572..45b5d4f626c93 100644 --- a/lib/msf/util/windows_crypto_helpers.rb +++ b/lib/msf/util/windows_crypto_helpers.rb @@ -109,6 +109,7 @@ def decrypt_lsa_data(policy_secret, lsa_key) (60...policy_secret.length).step(16) do |i| aes.reset aes.padding = 0 + aes.iv = "\x00" * 16 decrypted_data << aes.update(policy_secret[i,16]) end diff --git a/lib/msfenv.rb b/lib/msfenv.rb index d891365b9df41..07b99c8cea883 100644 --- a/lib/msfenv.rb +++ b/lib/msfenv.rb @@ -1,6 +1,11 @@ # Use bundler to load dependencies # +# Enable legacy providers such as blowfish-cbc, cast128-cbc, arcfour, etc +ENV['OPENSSL_CONF'] = File.expand_path( + File.join(File.dirname(__FILE__), '..', 'config', 'openssl.conf') +) + # Override the normal rails default, so that msfconsole will come up in production mode instead of development mode # unless the `--environment` flag is passed. ENV['RAILS_ENV'] ||= 'production' diff --git a/lib/rex/proto/rfb/cipher.rb b/lib/rex/proto/rfb/cipher.rb index 48c450fb65297..d2b609b2fe88e 100644 --- a/lib/rex/proto/rfb/cipher.rb +++ b/lib/rex/proto/rfb/cipher.rb @@ -83,14 +83,30 @@ def self.encrypt_ard(username, password, generator, key_length, prime_modulus, p user_struct = username + ("\0" * (64 - username.length)) + password + ("\0" * (64 - password.length)) - dh_peer = OpenSSL::PKey::DH.new(key_length * 8, generator) - dh_peer.set_key(peer_public_key, nil) - - dh = OpenSSL::PKey::DH.new(dh_peer) - dh.set_pqg(prime_modulus, nil, generator) - dh.generate_key! - - shared_key = dh.compute_key(dh_peer.pub_key) + # OpenSSL 3.0+ + if OpenSSL::PKey.respond_to?(:generate_key) + dh = OpenSSL::PKey::DH.new( + OpenSSL::ASN1::Sequence( + [ + OpenSSL::ASN1::Integer(prime_modulus), + OpenSSL::ASN1::Integer(generator), + ] + ).to_der + ) + dh = OpenSSL::PKey.generate_key(dh) + + shared_key = dh.compute_key(peer_public_key) + else + dh_peer = OpenSSL::PKey::DH.new(key_length * 8, generator) + dh_peer.set_key(peer_public_key, nil) + dh_peer_pub_key = dh_peer.pub_key + + dh = OpenSSL::PKey::DH.new(dh_peer) + dh.set_pqg(prime_modulus, nil, generator) + dh.generate_key! + + shared_key = dh.compute_key(dh_peer_pub_key) + end md5 = OpenSSL::Digest.new('MD5') key_digest = md5.digest(shared_key) diff --git a/modules/auxiliary/scanner/ssl/openssl_heartbleed.rb b/modules/auxiliary/scanner/ssl/openssl_heartbleed.rb index 8df078ab5e83a..dceeec46d6b1d 100644 --- a/modules/auxiliary/scanner/ssl/openssl_heartbleed.rb +++ b/modules/auxiliary/scanner/ssl/openssl_heartbleed.rb @@ -648,23 +648,30 @@ def get_factors(data, n) # Generates the private key from the P, Q and E values def key_from_pqe(p, q, e) - # Returns an RSA Private Key from Factors - key = OpenSSL::PKey::RSA.new() - key.set_factors(p, q) - - n = key.p * key.q - phi = (key.p - 1) * (key.q - 1 ) + n = p * q + phi = (p - 1) * (q - 1 ) d = OpenSSL::BN.new(e).mod_inverse(phi) - key.set_key(n, e, d) - - dmp1 = key.d % (key.p - 1) - dmq1 = key.d % (key.q - 1) - iqmp = key.q.mod_inverse(key.p) + dmp1 = d % (p - 1) + dmq1 = d % (q - 1) + iqmp = q.mod_inverse(p) - key.set_crt_params(dmp1, dmq1, iqmp) + asn1 = OpenSSL::ASN1::Sequence( + [ + OpenSSL::ASN1::Integer(0), + OpenSSL::ASN1::Integer(n), + OpenSSL::ASN1::Integer(e), + OpenSSL::ASN1::Integer(d), + OpenSSL::ASN1::Integer(p), + OpenSSL::ASN1::Integer(q), + OpenSSL::ASN1::Integer(dmp1), + OpenSSL::ASN1::Integer(dmq1), + OpenSSL::ASN1::Integer(iqmp) + ] + ) - return key + key = OpenSSL::PKey::RSA.new(asn1.to_der) + key end # diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index c1d0c9f9e7c40..2748930d99c01 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,4 +1,10 @@ # -*- coding: binary -*- + +# Enable legacy providers such as blowfish-cbc, cast128-cbc, arcfour, etc +ENV['OPENSSL_CONF'] = File.expand_path( + File.join(File.dirname(__FILE__), '..', 'config', 'openssl.conf') +) + require 'stringio' require 'factory_bot' require 'rubocop'