Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/lib/msf/ui/console/command_dispatcher/db/certs.rb
Views: 18756
# -*- coding: binary -*-12module Msf::Ui::Console::CommandDispatcher::Db::Certs3#4# Tab completion for the certs command5#6# @param str [String] the string currently being typed before tab was hit7# @param words [Array<String>] the previously completed words on the command line. words is always8# at least 1 when tab completion has reached this stage since the command itself has been completed9def cmd_certs_tabs(str, words)10tabs = []1112case words.length13when 114tabs = @@certs_opts.option_keys.select { |opt| opt.start_with?(str) }15when 216tabs = if words[1] == '-e' || words[1] == '--export'17tab_complete_filenames(str, words)18else19[]20end21end2223tabs24end2526def cmd_certs_help27print_line 'List Pkcs12 certificate bundles in the database'28print_line 'Usage: certs [options] [username[@domain_upn_format]]'29print_line30print @@certs_opts.usage31print_line32end3334@@certs_opts = Rex::Parser::Arguments.new(35['-v', '--verbose'] => [false, 'Verbose output'],36['-d', '--delete'] => [ false, 'Delete *all* matching pkcs12 entries'],37['-h', '--help'] => [false, 'Help banner'],38['-i', '--index'] => [true, 'Pkcs12 entry ID(s) to search for, e.g. `-i 1` or `-i 1,2,3` or `-i 1 -i 2 -i 3`'],39['-a', '--activate'] => [false, 'Activates *all* matching pkcs12 entries'],40['-A', '--deactivate'] => [false, 'Deactivates *all* matching pkcs12 entries'],41['-e', '--export'] => [true, 'The file path where to export the matching pkcs12 entry']42)4344def cmd_certs(*args)45return unless active?4647entries_affected = 048mode = :list49id_search = []50username = nil51verbose = false52export_path = nil53@@certs_opts.parse(args) do |opt, _idx, val|54case opt55when '-h', '--help'56cmd_certs_help57return58when '-v', '--verbose'59verbose = true60when '-d', '--delete'61mode = :delete62when '-i', '--id'63id_search = (id_search + val.split(/,\s*|\s+/)).uniq # allows 1 or 1,2,3 or "1 2 3" or "1, 2, 3"64when '-a', '--activate'65mode = :activate66when '-A', '--deactivate'67mode = :deactivate68when '-e', '--export'69export_path = val70else71# Anything that wasn't an option is a username to search for72username = val73end74end7576pkcs12_results = pkcs12_search(username: username, id_search: id_search)7778print_line('Pkcs12')79print_line('======')8081if mode == :delete82result = pkcs12_storage.delete(ids: pkcs12_results.map(&:id))83entries_affected = result.size84end8586if mode == :activate || mode == :deactivate87pkcs12_results = set_pkcs12_status(mode, pkcs12_results)88entries_affected = pkcs12_results.size89end9091if export_path92if pkcs12_results.empty?93print_error('No mathing Pkcs12 entry to export')94return95end96if pkcs12_results.size > 197print_error('More than one mathing Pkcs12 entry found. Filter with `-i` and/or provide a username')98return99end100101raw_data = Base64.strict_decode64(pkcs12_results.first.private_cred.data)102::File.binwrite(::File.expand_path(export_path), raw_data)103return104end105106if pkcs12_results.empty?107print_line('No Pkcs12')108print_line109return110end111112if verbose113pkcs12_results.each.with_index do |pkcs12_result, index|114print_line "Certificate[#{index}]:"115print_line pkcs12_result.openssl_pkcs12.certificate.to_s116print_line pkcs12_result.openssl_pkcs12.certificate.to_text117print_line118end119else120tbl = Rex::Text::Table.new(121{122'Columns' => ['id', 'username', 'realm', 'subject', 'issuer', 'ADCS CA', 'ADCS Template', 'status'],123'SortIndex' => -1,124'WordWrap' => false,125'Rows' => pkcs12_results.map do |pkcs12|126[127pkcs12.id,128pkcs12.username,129pkcs12.realm,130pkcs12.openssl_pkcs12.certificate.subject.to_s,131pkcs12.openssl_pkcs12.certificate.issuer.to_s,132pkcs12.adcs_ca,133pkcs12.adcs_template,134pkcs12_status(pkcs12)135]136end137}138)139print_line(tbl.to_s)140end141142case mode143when :delete144print_status("Deleted #{entries_affected} #{entries_affected > 1 ? 'entries' : 'entry'}") if entries_affected > 0145when :activate146print_status("Activated #{entries_affected} #{entries_affected > 1 ? 'entries' : 'entry'}") if entries_affected > 0147when :deactivate148print_status("Deactivated #{entries_affected} #{entries_affected > 1 ? 'entries' : 'entry'}") if entries_affected > 0149end150end151152153# @param [String, nil] username Search for pkcs12 associated with this username154# @param [Array<Integer>, nil] id_search List of pkcs12 IDs to search for155# @param [Workspace] workspace to search against156# @option [Symbol] :workspace The framework.db.workspace to search against (optional)157# @return [Array<>]158def pkcs12_search(username: nil, id_search: nil, workspace: framework.db.workspace)159pkcs12_results = []160161if id_search.present?162begin163pkcs12_results += id_search.flat_map do |id|164pkcs12_storage.pkcs12(165workspace: workspace,166id: id167)168end169rescue ActiveRecord::RecordNotFound => e170wlog("Record Not Found: #{e.message}")171print_warning("Not all records with the ids: #{id_search} could be found.")172print_warning('Please ensure all ids specified are available.')173end174elsif username.present?175realm = nil176if username.include?('@')177username, realm = username.split('@', 2)178end179pkcs12_results += pkcs12_storage.pkcs12(180workspace: workspace,181username: username,182realm: realm183)184else185pkcs12_results += pkcs12_storage.pkcs12(186workspace: workspace187)188end189190pkcs12_results.sort_by do |pkcs12|191[pkcs12.realm, pkcs12.username]192end193end194195196private197198# @return [Msf::Exploit::Remote::Kerberos::Ticket::Storage::ReadWrite]199def pkcs12_storage200@pkcs12_storage ||= Msf::Exploit::Remote::Pkcs12::Storage.new(framework: framework)201end202203# Gets the status of a Pkcs12204#205# @param [Msf::Exploit::Remote::Pkcs12::Storage]206# @return [String] Status of the Pkcs12207def pkcs12_status(pkcs12)208if pkcs12.expired?209'>>expired<<'210elsif pkcs12.status.blank?211'active'212else213pkcs12.status214end215end216217# Sets the status of the Pkcs12218#219# @param [Symbol] mode The status (:activate or :deactivate) to apply to the Pkcs12(s)220# @param [Array<StoredPkcs12>] tickets The Pkcs12 which statuses are to be updated221# @return [Array<StoredPkcs12>]222def set_pkcs12_status(mode, pkcs12)223if mode == :activate224pkcs12_storage.activate(ids: pkcs12.map(&:id))225elsif mode == :deactivate226pkcs12_storage.deactivate(ids: pkcs12.map(&:id))227end228end229end230231232