Class: Msf::Exploit::Remote::HTTP::Kubernetes::Output::Table

Inherits:
Object
  • Object
show all
Defined in:
lib/msf/core/exploit/remote/http/kubernetes/output/table.rb

Overview

Outputs Kubernetes API responses in table format

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(output, highlight_name_pattern: nil) ⇒ Table

Creates a new `Msf::Exploit::Remote::HTTP::Kubernetes::Output::Table` instance

Parameters:

  • output (object)

    The original output object with print_line/print_status/etc methods available.

  • highlight_name_pattern (String) (defaults to: nil)

    The regex used to highlight noteworthy resource names


10
11
12
13
# File 'lib/msf/core/exploit/remote/http/kubernetes/output/table.rb', line 10

def initialize(output, highlight_name_pattern: nil)
  @output = output
  @highlight_name_pattern = highlight_name_pattern
end

Instance Attribute Details

#highlight_name_patternObject (readonly, protected)

Returns the value of attribute highlight_name_pattern.


143
144
145
# File 'lib/msf/core/exploit/remote/http/kubernetes/output/table.rb', line 143

def highlight_name_pattern
  @highlight_name_pattern
end

#outputObject (readonly, protected)

Returns the value of attribute output.


143
144
145
# File 'lib/msf/core/exploit/remote/http/kubernetes/output/table.rb', line 143

def output
  @output
end

Instance Method Details

#create_table(options) ⇒ Object (protected)


145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/msf/core/exploit/remote/http/kubernetes/output/table.rb', line 145

def create_table(options)
  default_options = {
    'Indent' => indent_level,
    # For now, don't perform any word wrapping on the table as it breaks the workflow of
    # copying container/secret names
    'WordWrap' => false,
    'ColProps' => {
      'data' => {
        'Stylers' => [
          Msf::Ui::Console::TablePrint::HighlightSubstringStyler.new([highlight_name_pattern])
        ]
      },
      'name' => {
        'Stylers' => [
          Msf::Ui::Console::TablePrint::HighlightSubstringStyler.new([highlight_name_pattern])
        ]
      },
      'age' => {
        'Formatters' => [
          Msf::Ui::Console::TablePrint::AgeFormatter.new
        ]
      }
    }
  }

  Rex::Text::Table.new(default_options.merge(options))
end

#get_claim_as_rows(hash, parent_keys: []) ⇒ Object (protected)


187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/msf/core/exploit/remote/http/kubernetes/output/table.rb', line 187

def get_claim_as_rows(hash, parent_keys: [])
  return [] if hash.empty?

  result = []
  hash.each_pair do |key, value|
    if value.is_a?(Hash)
      result += get_claim_as_rows(value, parent_keys: parent_keys + [key])
    else
      result << [(parent_keys + [key.to_s]).join('.'), value]
    end
  end

  result
end

#indent_levelObject (protected)


173
174
175
# File 'lib/msf/core/exploit/remote/http/kubernetes/output/table.rb', line 173

def indent_level
  2
end

Print the auth rules returned from a kubernetes client in the same format as `kubectl auth can-i –list –namespace default -v8`


79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/msf/core/exploit/remote/http/kubernetes/output/table.rb', line 79

def print_auth(namespace, auth)
  auth_table = Msf::Exploit::Remote::HTTP::Kubernetes::AuthParser.new(auth).as_table

  table = create_table(
    'Header' => "Auth (namespace: #{namespace})",
    # The table rows will already be sorted, disable the default sorting logic
    'SortIndex' => -1,
    'Columns' => auth_table[:columns],
    'Rows' => auth_table[:rows]
  )

  print_table(table)
end

35
36
37
38
39
40
41
42
43
# File 'lib/msf/core/exploit/remote/http/kubernetes/output/table.rb', line 35

def print_claims(claims)
  table = create_table(
    'Header' => 'Token Claims',
    'Columns' => ['name', 'value'],
    'Rows' => get_claim_as_rows(claims)
  )

  print_table(table)
end

27
28
29
30
31
32
33
# File 'lib/msf/core/exploit/remote/http/kubernetes/output/table.rb', line 27

def print_enum_failure(resource, error)
  if error.is_a?(Msf::Exploit::Remote::HTTP::Kubernetes::Error::ApiError)
    print_status("#{resource} failure - #{error.message}")
  else
    output.print_error(error.message)
  end
end

15
16
17
# File 'lib/msf/core/exploit/remote/http/kubernetes/output/table.rb', line 15

def print_error(*args)
  output.print_error(*args)
end

19
20
21
# File 'lib/msf/core/exploit/remote/http/kubernetes/output/table.rb', line 19

def print_good(*args)
  output.print_good(*args)
end

61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/msf/core/exploit/remote/http/kubernetes/output/table.rb', line 61

def print_namespaces(namespaces)
  table = create_table(
    'Header' => 'Namespaces',
    'Columns' => ['#', 'name']
  )

  namespaces.each.with_index do |item, i|
    table << [
      i,
      item.dig(:metadata, :name)
    ]
  end

  print_table(table)
end

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
# File 'lib/msf/core/exploit/remote/http/kubernetes/output/table.rb', line 93

def print_pods(namespace, pods)
  table = create_table(
    'Header' => "Pods (namespace: #{namespace})",
    'Columns' => ['#', 'namespace', 'name', 'status', 'containers', 'ip']
  )

  pods.each.with_index do |item, i|
    containers = item.dig(:spec, :containers).map do |container|
      ports = container.fetch(:ports, []).map do |ports|
        "#{ports[:protocol]}:#{ports[:containerPort]}"
      end.uniq
      details = "image: #{container[:image]}"
      details << " #{ports.join(',')}" if ports.any?
      "#{container[:name]} (#{details})"
    end
    table << [
      i,
      namespace,
      item.dig(:metadata, :name),
      item.dig(:status, :phase),
      containers.join(', '),
      (item.dig(:status, :podIPs) || []).map { |ip| ip[:ip] }.join(',')
    ]
  end

  print_table(table)
end

121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/msf/core/exploit/remote/http/kubernetes/output/table.rb', line 121

def print_secrets(namespace, secrets)
  table = create_table(
    'Header' => "Secrets (namespace: #{namespace})",
    'Columns' => ['#', 'namespace', 'name', 'type', 'data', 'age']
  )

  secrets.each.with_index do |item, i|
    table << [
      i,
      namespace,
      item.dig(:metadata, :name),
      item[:type],
      item.fetch(:data, {}).keys.join(','),
      item.dig(:metadata, :creationTimestamp)
    ]
  end

  print_table(table)
end

23
24
25
# File 'lib/msf/core/exploit/remote/http/kubernetes/output/table.rb', line 23

def print_status(*args)
  output.print_status(*args)
end

181
182
183
184
185
# File 'lib/msf/core/exploit/remote/http/kubernetes/output/table.rb', line 181

def print_table(table)
  output.print(table.to_s)
  output.print_line("#{' ' * indent_level}No rows") if table.rows.empty?
  output.print_line
end

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/msf/core/exploit/remote/http/kubernetes/output/table.rb', line 45

def print_version(version)
  table = create_table(
    'Header' => 'Server API Version',
    'Columns' => ['name', 'value']
  )

  version.each_pair do |key, value|
    table << [
      key,
      value
    ]
  end

  print_table(table)
end

#with_indent(string, amount = indent_level) ⇒ Object (protected)


177
178
179
# File 'lib/msf/core/exploit/remote/http/kubernetes/output/table.rb', line 177

def with_indent(string, amount = indent_level)
  "#{' ' * amount}#{string}"
end