Module: Msf::Post::Azure

Defined in:
lib/msf/core/post/azure.rb

Instance Method Summary collapse

Instance Method Details

Print any lines from a ConsoleHost_history.txt file that may have important information

Parameters:

  • content (Str)

    contents of a ConsoleHost_history.txt file

Returns:

  • Array of strings to print to notify the user about



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/msf/core/post/azure.rb', line 75

def print_consolehost_history(content)
  # a list of strings which may contain secrets or other important information
  commands_of_value = [
    'System.Management.Automation.PSCredential', # for creating new credentials, may contain username/password
    'ConvertTo-SecureString', # often used with passwords
    'Connect-AzAccount', # may contain an access token in line or near it
    'New-PSSession', # may indicate lateral movement to a new host
    'commandToExecute', # when used with Set-AzVMExtension and a CustomScriptExtension, may show code execution
    '-ScriptBlock' # when used with Invoke-Command, may show code execution
  ]

  output = []

  content.each_line.with_index do |line, index|
    commands_of_value.each do |command|
      if line.downcase.include? command.downcase
        output.append("Line #{index + 1} may contain sensitive information. Manual search recommended, keyword hit: #{command}")
      end
    end
  end
  output
end

#process_context_contents(content) ⇒ Array

Processes a hashtable (json) generated via Save-AzContext or automatically generated in AzureRmContext.json

Parameters:

  • content (Hash)

    contents of a json file to process

Returns:

  • (Array)


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/msf/core/post/azure.rb', line 45

def process_context_contents(content)
  table_data = []

  # make sure we have keys we expect to
  return table_data unless content.key? 'Contexts'

  content['Contexts'].each_value do ||
    username = .dig('Account', 'Id')
    type = .dig('Account', 'Type')
    principal_secret = .dig('Account', 'ExtendedProperties', 'ServicePrincipalSecret') # only in 'ServicePrincipal' types
    access_token = .dig('Account', 'ExtendedProperties', 'AccessToken')
    graph_access_token = .dig('Account', 'ExtendedProperties', 'GraphAccessToken')
    # example of parsing these out to get an expiration for the token
    # unless graph_access_token.nil? || graph_access_token.empty?
    #   decoded_token = Msf::Exploit::Remote::HTTP::JWT.decode(graph_access_token)
    #   graph_access_token_exp = Time.at(decoded_token.payload['exp']).to_datetime
    # end
    ms_graph_access_token = .dig('Account', 'ExtendedProperties', 'MicrosoftGraphAccessToken')
    key_vault_token = .dig('Account', 'ExtendedProperties', 'KeyVault')
    table_data.append([username, type, access_token, graph_access_token, ms_graph_access_token, key_vault_token, principal_secret])
  end
  table_data
end

#process_profile_file(content) ⇒ Array

Processes a hashtable (json) from azureProfile.json

Parameters:

  • content (Hash)

    contents of a json file to process

Returns:

  • (Array)


27
28
29
30
31
32
33
34
35
36
37
# File 'lib/msf/core/post/azure.rb', line 27

def process_profile_file(content)
  table_data = []

  # make sure we have keys we expect to
  return table_data unless content.key? 'subscriptions'

  content['subscriptions'].each do |item|
    table_data << [item['name'], item.dig('user', 'name'), item['environmentName']]
  end
  table_data
end

#process_tokens_file(content) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/msf/core/post/azure.rb', line 4

def process_tokens_file(content)
  table_data = []

  dic = {}
  content.each do |item|
    if dic.key?(item['userId'])
      dic[item['userId']] = dic[item['userId']] + 1
    else
      dic[item['userId']] = 1
    end
  end
  dic.each do |key, value|
    table_data << [file_path, key, value]
  end

  table_data
end