-
Notifications
You must be signed in to change notification settings - Fork 14.7k
Added SNI support for the ssl_version scanner #20511
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added SNI support for the ssl_version scanner #20511
Conversation
| ctx = { 'Msf' => framework, 'MsfExploit' => self } | ||
| # Initialize rex-sslscan scanner | ||
| scanner = Rex::SSLScan::Scanner.new(ip, rport, ctx) | ||
| scanner = Rex::SSLScan::Scanner.new(ip, rport, ctx, tls_server_name_indication: datastore['RHOSTNAME']) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'll want to add this to the datastore options so it appears to the user when they run show options command as well adding validation etc, similar to this module:
| OptString.new('SSLServerNameIndication', [ false, 'SSL/TLS Server Name Indication (SNI)', nil]), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adfoster-r7 i have added SSLServerNameIndication as an option OptString.new('SSLServerNameIndication', [ true, 'SSL/TLS Server Name Indication (SNI)', nil])
| ctx = { 'Msf' => framework, 'MsfExploit' => self } | ||
| # Initialize rex-sslscan scanner | ||
| scanner = Rex::SSLScan::Scanner.new(ip, rport, ctx) | ||
| scanner = Rex::SSLScan::Scanner.new(ip, rport, ctx, tls_server_name_indication: datastore['RHOSTNAME']) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies, my brain autocompleted datastore['RHOSTNAME'] as datastore['SSLServerNameIndication'].
For context, we've got an existing convention of SSLServerNameIndication that you'll want to follow - that's what my original comment was aimed at following 👍
https://github.com/search?q=repo%3Arapid7%2Fmetasploit-framework%20SSLServerNameIndication&type=code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adfoster-r7 i have added SSLServerNameIndication as an option OptString.new('SSLServerNameIndication', [ true, 'SSL/TLS Server Name Indication (SNI)', nil])
df38f28 to
8469613
Compare
smcintyre-r7
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes look good. There does appear to be an unrelated exception that's raised though when RHOSTS is set to a hostname and a database is connected that we should fix eventually.
Exception Info
[*] lab.zerosteiner.com:443 - Scanned 1 of 1 hosts (100% complete)
[-] Auxiliary failed: ActiveRecord::StatementInvalid PG::InvalidTextRepresentation: ERROR: invalid input syntax for type inet: "lab.zerosteiner.com"
CONTEXT: unnamed portal parameter $2 = '...'
[-] Call stack:
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:894:in `exec_params'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:894:in `block (2 levels) in exec_no_cache'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:1004:in `block in with_raw_connection'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activesupport-7.2.2.1/lib/active_support/concurrency/null_lock.rb:9:in `synchronize'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:976:in `with_raw_connection'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:893:in `block in exec_no_cache'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activesupport-7.2.2.1/lib/active_support/notifications/instrumenter.rb:58:in `instrument'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:1119:in `log'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:892:in `exec_no_cache'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:872:in `execute_and_clear'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:66:in `internal_exec_query'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/database_statements.rb:647:in `select'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/database_statements.rb:73:in `select_all'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/query_cache.rb:251:in `select_all'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/querying.rb:70:in `_query_by_sql'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1431:in `block (2 levels) in exec_main_query'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:415:in `with_connection'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/connection_handling.rb:296:in `with_connection'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1430:in `block in exec_main_query'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1452:in `skip_query_cache_if_necessary'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1414:in `exec_main_query'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1392:in `block in exec_queries'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1452:in `skip_query_cache_if_necessary'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1386:in `exec_queries'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/association_relation.rb:44:in `exec_queries'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:1167:in `load'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:336:in `records'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/relation.rb:331:in `to_ary'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/relation/finder_methods.rb:615:in `find_nth_with_limit'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/relation/finder_methods.rb:600:in `find_nth'
[-] /home/smcintyre/.rvm/gems/ruby-3.3.8@metasploit-framework/gems/activerecord-7.2.2.1/lib/active_record/relation/finder_methods.rb:177:in `first'
[-] /home/smcintyre/Repositories/metasploit-framework.pr/lib/msf/core/db_manager/exploit_attempt.rb:65:in `report_exploit_failure'
[-] /home/smcintyre/Repositories/metasploit-framework.pr/lib/metasploit/framework/data_service/proxy/exploit_data_proxy.rb:17:in `block in report_exploit_failure'
[-] /home/smcintyre/Repositories/metasploit-framework.pr/lib/metasploit/framework/data_service/proxy/core.rb:164:in `data_service_operation'
[-] /home/smcintyre/Repositories/metasploit-framework.pr/lib/metasploit/framework/data_service/proxy/exploit_data_proxy.rb:15:in `report_exploit_failure'
[-] /home/smcintyre/Repositories/metasploit-framework.pr/lib/msf/core/module/failure.rb:69:in `report_failure'
msf auxiliary(scanner/ssl/ssl_version) >
If you want to look at the feedback, we can get this landed. Thanks for this fix!
|
|
||
| register_options( | ||
| [ | ||
| OptString.new('SSLServerNameIndication', [ true, 'SSL/TLS Server Name Indication (SNI)', nil]), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this actually needs to be required. I was able to test another server that didn't have SNI enabled and I can scan it when this option is blank or incorrect.
msf auxiliary(scanner/ssl/ssl_version) > run SSLServerNameIndication='' RHOSTS=192.168.249.7
[*] 192.168.249.7:443 - Starting enhanced SSL/TLS scan of 192.168.249.7:443
[*] 192.168.249.7:443 - Certificate Information:
[*] 192.168.249.7:443 - Subject: /CN=zerosteiner.com
[*] 192.168.249.7:443 - Issuer: /C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http:\/\/certs.godaddy.com\/repository\//CN=Go Daddy Secure Certificate Authority - G2
[*] 192.168.249.7:443 - Signature Alg: sha256WithRSAEncryption
[*] 192.168.249.7:443 - Public Key Size: 4096 bits
[*] 192.168.249.7:443 - Not Valid Before: 2025-07-13 18:52:26 UTC
[*] 192.168.249.7:443 - Not Valid After: 2026-08-14 18:52:26 UTC
[*] 192.168.249.7:443 - CA Issuer: http://certificates.godaddy.com/repository/gdig2.crt
[*] 192.168.249.7:443 - Has common name zerosteiner.com
[+] 192.168.249.7:443 - Certificate saved to loot: /home/smcintyre/.msf4/loot/20250903162942_default_192.168.249.7_ssl.certificate._316753.pem
[+] 192.168.249.7:443 - 192.168.249.7:443 - TLSv1_2 supported with 14 cipher(s)
[*] 192.168.249.7:443 - TLSv1_2: AES128-CCM (128 bits)
[*] 192.168.249.7:443 - TLSv1_2: ECDHE-RSA-AES256-GCM-SHA384 (256 bits)
[*] 192.168.249.7:443 - TLSv1_2: ECDHE-RSA-AES256-SHA (256 bits)
[*] 192.168.249.7:443 - TLSv1_2: ECDHE-RSA-AES128-GCM-SHA256 (128 bits)
[*] 192.168.249.7:443 - TLSv1_2: AES128-GCM-SHA256 (128 bits)
[*] 192.168.249.7:443 - TLSv1_2: AES256-GCM-SHA384 (256 bits)
[*] 192.168.249.7:443 - TLSv1_2: AES128-SHA (128 bits)
[*] 192.168.249.7:443 - TLSv1_2: AES256-CCM (256 bits)
[*] 192.168.249.7:443 - TLSv1_2: AES128-SHA256 (128 bits)
[*] 192.168.249.7:443 - TLSv1_2: ECDHE-RSA-CHACHA20-POLY1305 (256 bits)
[*] 192.168.249.7:443 - TLSv1_2: AES256-SHA256 (256 bits)
[*] 192.168.249.7:443 - TLSv1_2: ECDHE-RSA-AES128-SHA (128 bits)
[*] 192.168.249.7:443 - TLSv1_2: AES256-SHA (256 bits)
[*] 192.168.249.7:443 - TLSv1_2: ECDHE-RSA-AES128-SHA256 (128 bits)
[+] 192.168.249.7:443 - Detailed scan results saved to loot: /home/smcintyre/.msf4/loot/20250903162942_default_192.168.249.7_ssl.scan.rex_ssl_916679.json
[*] 192.168.249.7:443 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf auxiliary(scanner/ssl/ssl_version) > run SSLServerNameIndication='wrongwrong' RHOSTS=192.168.249.7
[*] 192.168.249.7:443 - Starting enhanced SSL/TLS scan of 192.168.249.7:443
[*] 192.168.249.7:443 - Certificate Information:
[*] 192.168.249.7:443 - Subject: /CN=zerosteiner.com
[*] 192.168.249.7:443 - Issuer: /C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http:\/\/certs.godaddy.com\/repository\//CN=Go Daddy Secure Certificate Authority - G2
[*] 192.168.249.7:443 - Signature Alg: sha256WithRSAEncryption
[*] 192.168.249.7:443 - Public Key Size: 4096 bits
[*] 192.168.249.7:443 - Not Valid Before: 2025-07-13 18:52:26 UTC
[*] 192.168.249.7:443 - Not Valid After: 2026-08-14 18:52:26 UTC
[*] 192.168.249.7:443 - CA Issuer: http://certificates.godaddy.com/repository/gdig2.crt
[*] 192.168.249.7:443 - Has common name zerosteiner.com
[+] 192.168.249.7:443 - Certificate saved to loot: /home/smcintyre/.msf4/loot/20250903163020_default_192.168.249.7_ssl.certificate._632585.pem
[+] 192.168.249.7:443 - 192.168.249.7:443 - TLSv1_2 supported with 14 cipher(s)
[*] 192.168.249.7:443 - TLSv1_2: ECDHE-RSA-AES256-GCM-SHA384 (256 bits)
[*] 192.168.249.7:443 - TLSv1_2: ECDHE-RSA-AES128-GCM-SHA256 (128 bits)
[*] 192.168.249.7:443 - TLSv1_2: ECDHE-RSA-AES256-SHA (256 bits)
[*] 192.168.249.7:443 - TLSv1_2: ECDHE-RSA-AES128-SHA256 (128 bits)
[*] 192.168.249.7:443 - TLSv1_2: AES128-CCM (128 bits)
[*] 192.168.249.7:443 - TLSv1_2: AES128-SHA (128 bits)
[*] 192.168.249.7:443 - TLSv1_2: AES128-SHA256 (128 bits)
[*] 192.168.249.7:443 - TLSv1_2: AES256-CCM (256 bits)
[*] 192.168.249.7:443 - TLSv1_2: AES256-GCM-SHA384 (256 bits)
[*] 192.168.249.7:443 - TLSv1_2: ECDHE-RSA-CHACHA20-POLY1305 (256 bits)
[*] 192.168.249.7:443 - TLSv1_2: ECDHE-RSA-AES128-SHA (128 bits)
[*] 192.168.249.7:443 - TLSv1_2: AES256-SHA (256 bits)
[*] 192.168.249.7:443 - TLSv1_2: AES256-SHA256 (256 bits)
[*] 192.168.249.7:443 - TLSv1_2: AES128-GCM-SHA256 (128 bits)
[+] 192.168.249.7:443 - Detailed scan results saved to loot: /home/smcintyre/.msf4/loot/20250903163020_default_192.168.249.7_ssl.scan.rex_ssl_623174.json
[*] 192.168.249.7:443 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf auxiliary(scanner/ssl/ssl_version) >
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@smcintyre-r7 I have adjusted the option and set it to not required
| ctx = { 'Msf' => framework, 'MsfExploit' => self } | ||
| # Initialize rex-sslscan scanner | ||
| scanner = Rex::SSLScan::Scanner.new(ip, rport, ctx) | ||
| scanner = Rex::SSLScan::Scanner.new(ip, rport, ctx, tls_server_name_indication: datastore['SSLServerNameIndication']) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once SSLServerNameIndication is made optional, would it be possible to do something like this? This would allow the option to explicitly be set from the datastore, but if the user doesn't set it, the RHOSTNAME from RangeWalker would be used by default in the event that they're targeting a host by it's name making it more convenient to use.
| scanner = Rex::SSLScan::Scanner.new(ip, rport, ctx, tls_server_name_indication: datastore['SSLServerNameIndication']) | |
| tls_server_name_indication = nil | |
| tls_server_name_indication = datastore['SSLServerNameIndication'] if tls_server_name_indication.nil? and datastore['SSLServerNameIndication'].present? | |
| tls_server_name_indication = datastore['RHOSTNAME'] if tls_server_name_indication.nil? and datastore['RHOSTNAME'].present? | |
| scanner = Rex::SSLScan::Scanner.new(ip, rport, ctx, tls_server_name_indication: tls_server_name_indication) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's roughly the approach taken elsewhere too:
| 'PeerHostname' => opts['SSLServerNameIndication'] || opts['VHOST'] || opts['RHOSTNAME'], |
It's maybe worth noting that Pro doesn't currently use the rhost walker for IP expansion, so RHOSTNAME wouldn't be set automatically by Pro with its current implementation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once
SSLServerNameIndicationis made optional, would it be possible to do something like this? This would allow the option to explicitly be set from the datastore, but if the user doesn't set it, the RHOSTNAME from RangeWalker would be used by default in the event that they're targeting a host by it's name making it more convenient to use.
@smcintyre-r7 thank you for the proposal, i have added this to the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's roughly the approach taken elsewhere too:
'PeerHostname' => opts['SSLServerNameIndication'] || opts['VHOST'] || opts['RHOSTNAME'], It's maybe worth noting that Pro doesn't currently use the rhost walker for IP expansion, so RHOSTNAME wouldn't be set automatically by Pro with its current implementation
@adfoster-r7 i have created a task for it
8469613 to
bf959c1
Compare
| begin | ||
| ctx = { 'Msf' => framework, 'MsfExploit' => self } | ||
| tls_server_name_indication = nil | ||
| tls_server_name_indication = datastore['SSLServerNameIndication'] if tls_server_name_indication.nil? && datastore['SSLServerNameIndication'].present? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| tls_server_name_indication = datastore['SSLServerNameIndication'] if tls_server_name_indication.nil? && datastore['SSLServerNameIndication'].present? | |
| tls_server_name_indication = datastore['SSLServerNameIndication'] if datastore['SSLServerNameIndication'].present? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dwelch-r7 Adjusted the code and removed the unnecessary tls_server_name_indication check
bf959c1 to
9fb4966
Compare
smcintyre-r7
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New changes look good and the pattern you implement will be pretty convenient for framework users. Thanks for these updates!
Release NotesThis fixes SNI functionality in the |
This PR fixes missing SNI support for the ssl_version scanner.
Verification
msfconsoleuse auxiliary/scanner/ssl/ssl_versionset rhosts localhost- target server with weak certificates and ciphers enabled, default port is 443. Use hostnameset SSLServerNameIndication localhostrunset rhosts 127.0.0.1- target server with weak certificates and ciphers enabled, default port is 443. Use server's IP addressset SSLServerNameIndication 127.0.0.1runset rhosts 127.0.0.1- target server with weak certificates and ciphers enabled, default port is 443. Use server's IP addressset SSLServerNameIndication localhostrun