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'],
  ['-t', '--trace'] => [true, 'Show trace output for a single Kerberos ticket by ID or path']
)

Instance Method Summary collapse

Instance Method Details

#cmd_klist(*args) ⇒ Object



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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/msf/ui/console/command_dispatcher/db/klist.rb', line 34

def cmd_klist(*args)
  return unless active?

  entries_affected = 0
  mode = :list
  host_ranges = []
  id_search = []
  verbose = false
  trace_target = nil
  @@klist_opts.parse(args) do |opt, _idx, val|
    case opt
    when '-h', '--help'
      cmd_klist_help
      return
    when '-v', '--verbose'
      verbose = true
    when '-t', '--trace'
      trace_target = val
    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?
  trace_path = nil
  if trace_target
    if trace_target.match?(/\A\d+\z/)
      id_search = [trace_target]
    else
      id_search = []
      trace_path = File.expand_path(trace_target)
    end
  end
  id_search = nil if id_search.empty?

  ticket_results = ticket_search(host_ranges, id_search)
  ticket_results.select! { |ticket_result| File.expand_path(ticket_result.path.to_s) == trace_path } if trace_path

  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)
    ticket_results.select! { |ticket_result| File.expand_path(ticket_result.path.to_s) == trace_path } if trace_path
  end

  if trace_target
    ticket_results.each.with_index do |ticket_result, index|
      presenter = Rex::Proto::Kerberos::CredentialCache::Krb5CcachePresenter.new(ticket_result.ccache)
      print_line presenter.present_trace(source: "Cache[#{index}] id=#{ticket_result.id}")
      print_line
    end
  elsif 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)



158
159
160
# File 'lib/msf/ui/console/command_dispatcher/db/klist.rb', line 158

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