diff --git a/lib/msf/core/exploit/remote/http/kubernetes/enumeration.rb b/lib/msf/core/exploit/remote/http/kubernetes/enumeration.rb index 652990208f..c7a51d41fc 100644 --- a/lib/msf/core/exploit/remote/http/kubernetes/enumeration.rb +++ b/lib/msf/core/exploit/remote/http/kubernetes/enumeration.rb @@ -7,12 +7,15 @@ module Msf::Exploit::Remote::HTTP::Kubernetes::Enumeration register_options( [ - Msf::OptString.new('NAMESPACE_LIST', [false, 'The default namespace list to iterate when the current token does not have the permission to retrieve the available namespaces', 'default,dev,staging,production,kube-node-lease,kube-lease,kube-system']) + Msf::OptString.new('NAMESPACE_LIST', [false, 'The default namespace list to iterate when the current token does not have the permission to retrieve the available namespaces', 'default,dev,staging,production,kube-public,kube-node-lease,kube-lease,kube-system']) ] ) end def enum_all + token_claims = parse_jwt(api_token) + output.print_claims(token_claims) if token_claims + enum_version namespace_items = enum_namespaces namespaces_name = namespace_items.map { |item| item.dig(:metadata, :name) } @@ -20,12 +23,11 @@ module Msf::Exploit::Remote::HTTP::Kubernetes::Enumeration # If there's no permissions to access namespaces, we can use the current token's namespace, # as well as trying some common namespaces if namespace_items.empty? - token_claims = parse_jwt(api_token) current_token_namespace = token_claims&.dig('kubernetes.io', 'namespace') possible_namespaces = (datastore['NAMESPACE_LIST'].split(',') + [current_token_namespace]).uniq.compact namespaces_name += possible_namespaces - output.print_error("No namespaces available. Attempting the current token's namespace and common namespaces: #{namespaces_name.join(', ')}") + output.print_error("Unable to extract namespaces. Attempting the current token's namespace and common namespaces: #{namespaces_name.join(', ')}") end # Split the information for each namespace separately @@ -163,7 +165,7 @@ module Msf::Exploit::Remote::HTTP::Kubernetes::Enumeration path = store_loot('tls.key', 'text/plain', nil, tls_key, "#{loot_name}.key") print_good("tls_key #{resource_name}: #{path}") - path = store_loot('tls.cert', 'text/plain', nil, tls_cert, "#{loot_name}.crt") + path = store_loot('tls.cert', 'application/x-pem-file', nil, tls_cert, "#{loot_name}.crt") print_good("tls_cert #{resource_name}: #{path} (#{tls_subject || 'No Subject'})") when Msf::Exploit::Remote::HTTP::Kubernetes::Secret::ServiceAccountToken data = secret[:data].clone diff --git a/lib/msf/core/exploit/remote/http/kubernetes/output/json.rb b/lib/msf/core/exploit/remote/http/kubernetes/output/json.rb index 434758a0e7..c5a7d2df31 100644 --- a/lib/msf/core/exploit/remote/http/kubernetes/output/json.rb +++ b/lib/msf/core/exploit/remote/http/kubernetes/output/json.rb @@ -23,6 +23,10 @@ class Msf::Exploit::Remote::HTTP::Kubernetes::Output::JSON end end + def print_claims(claims) + print_json(claims) + end + def print_version(version) print_json(version) end diff --git a/lib/msf/core/exploit/remote/http/kubernetes/output/table.rb b/lib/msf/core/exploit/remote/http/kubernetes/output/table.rb index 8e37db544f..cdef6d3c52 100644 --- a/lib/msf/core/exploit/remote/http/kubernetes/output/table.rb +++ b/lib/msf/core/exploit/remote/http/kubernetes/output/table.rb @@ -32,9 +32,19 @@ class Msf::Exploit::Remote::HTTP::Kubernetes::Output::Table end end + def print_claims(claims) + table = create_table( + 'Header' => 'Token Claims', + 'Columns' => ['name', 'value'], + 'Rows' => get_claim_as_rows(claims) + ) + + print_table(table) + end + def print_version(version) table = create_table( - 'Header' => 'Version', + 'Header' => 'Server API Version', 'Columns' => ['name', 'value'] ) @@ -173,4 +183,19 @@ class Msf::Exploit::Remote::HTTP::Kubernetes::Output::Table output.print_line("#{' ' * indent_level}No rows") if table.rows.empty? output.print_line end + + 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 end