Module: Msf::Ui::Console::CommandDispatcher::Db::Klist

Included in:
Msf::Ui::Console::CommandDispatcher::Db
Defined in:
lib/msf/ui/console/command_dispatcher/db/klist.rb

Constant Summary collapse

@@klist_opts =
Rex::Parser::Arguments.new(
  ['-v', '--verbose'] => [false, 'Verbose output'],
  ['-d', '--delete'] => [ false, 'Delete *all* matching kerberos entries'],
  ['-h', '--help'] => [false, 'Help banner'],
  ['-i', '--index'] => [true, 'Kerberos entry ID(s) to search for, e.g. `-i 1` or `-i 1,2,3` or `-i 1 -i 2 -i 3`'],
  ['-a', '--activate'] => [false, 'Activates *all* matching kerberos entries'],
  ['-A', '--deactivate'] => [false, 'Deactivates *all* matching kerberos entries']
)

Instance Method Summary collapse

Instance Method Details

#cmd_klist(*args) ⇒ Object



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/msf/ui/console/command_dispatcher/db/klist.rb', line 33

def cmd_klist(*args)
  return unless active?

  entries_affected = 0
  mode = :list
  host_ranges = []
  id_search = []
  verbose = false
  @@klist_opts.parse(args) do |opt, _idx, val|
    case opt
    when '-h', '--help'
      cmd_klist_help
      return
    when '-v', '--verbose'
      verbose = true
    when '-d', '--delete'
      mode = :delete
    when '-i', '--id'
      id_search = (id_search + val.split(/,\s*|\s+/)).uniq # allows 1 or 1,2,3 or "1 2 3" or "1, 2, 3"
    when '-a', '--activate'
      mode = :activate
    when '-A', '--deactivate'
      mode = :deactivate
    else
      # Anything that wasn't an option is a host to search for
      unless arg_host_range(val, host_ranges)
        return
      end
    end
  end

  # Sentinel value meaning all
  host_ranges.push(nil) if host_ranges.empty?
  id_search = nil if id_search.empty?

  ticket_results = ticket_search(host_ranges, id_search)

  print_line('Kerberos Cache')
  print_line('==============')

  if ticket_results.empty?
    print_line('No tickets')
    print_line
    return
  end

  if mode == :delete
    result = kerberos_ticket_storage.delete_tickets(ids: ticket_results.map(&:id))
    entries_affected = result.size
  end

  if mode == :activate || mode == :deactivate
    result = set_activation_status(mode, ticket_results)
    entries_affected = result.size
    # Update the contents of ticket results to display the updated status values
    # TODO: should be able to use the results returned from updating loot
    # but it returns a base 64'd data field which breaks when bindata tries to parse it as a ccache
    ticket_results = ticket_search(host_ranges, id_search)
  end

  if verbose
    ticket_results.each.with_index do |ticket_result, index|
      ticket_details = Rex::Proto::Kerberos::CredentialCache::Krb5CcachePresenter.new(ticket_result.ccache).present
      print_line "Cache[#{index}]:"
      print_line ticket_details.indent(2)
      print_line
    end
  else
    tbl = Rex::Text::Table.new(
      {
        'Columns' => ['id', 'host', 'principal', 'sname', 'enctype', 'issued', 'status', 'path'],
        'SortIndex' => -1,
        # For now, don't perform any word wrapping on the table as it breaks the workflow of
        # copying file paths and pasting them into applications
        'WordWrap' => false,
        'Rows' => ticket_results.map do |ticket|
          [
            ticket.id,
            ticket.host_address,
            ticket.principal,
            ticket.sname,
            Rex::Proto::Kerberos::Crypto::Encryption.const_name(ticket.enctype),
            ticket.starttime,
            ticket_status(ticket),
            ticket.path
          ]
        end
      }
    )
    print_line(tbl.to_s)
  end

  case mode
  when :delete
    print_status("Deleted #{entries_affected} #{entries_affected > 1 ? 'entries' : 'entry'}") if entries_affected > 0
  when :activate
    print_status("Activated #{entries_affected} #{entries_affected > 1 ? 'entries' : 'entry'}") if entries_affected > 0
  when :deactivate
    print_status("Deactivated #{entries_affected} #{entries_affected > 1 ? 'entries' : 'entry'}") if entries_affected > 0
  end
end

#cmd_klist_helpObject



16
17
18
19
20
21
22
# File 'lib/msf/ui/console/command_dispatcher/db/klist.rb', line 16

def cmd_klist_help
  print_line 'List Kerberos tickets in the database'
  print_line 'Usage: klist [options] [hosts]'
  print_line
  print @@klist_opts.usage
  print_line
end

#cmd_klist_tabs(str, words) ⇒ Object

Tab completion for the klist command

at least 1 when tab completion has reached this stage since the command itself has been completed

Parameters:

  • str (String)

    the string currently being typed before tab was hit

  • words (Array<String>)

    the previously completed words on the command line. words is always



10
11
12
13
14
# File 'lib/msf/ui/console/command_dispatcher/db/klist.rb', line 10

def cmd_klist_tabs(str, words)
  if words.length == 1
    @@klist_opts.option_keys.select { |opt| opt.start_with?(str) }
  end
end

#kerberos_ticket_storageMsf::Exploit::Remote::Kerberos::Ticket::Storage::ReadWrite (protected)



138
139
140
# File 'lib/msf/ui/console/command_dispatcher/db/klist.rb', line 138

def kerberos_ticket_storage
  @kerberos_ticket_storage ||= Msf::Exploit::Remote::Kerberos::Ticket::Storage::ReadWrite.new(framework: framework)
end