Skip to content

A Magento Setup for CVE Analysis

Posted on:June 11, 2023

This post is a companion piece to this blog post. You will learn how to make a setup to reproduce CVE-2022-24086 and CVE-2022-24087.

Key Takeaways

warden is excellent for Magento setups, try it out 💯

This setup was made on Linux, but warden could also work on MacOS.

Table of contents

Open Table of contents

Introduction

Bonjour!

To analyze Magento vulnerabilities, we need a cool Magento setup 🥳.

Searching on Google, the warden deployment tool is often cited as a quick way to deploy an instance using Docker containers.

The documentation is available here and is very complete. Make sure you have Docker installed (and running) and get warden:

git clone -b main https://github.com/wardenenv/warden.git
cd warden

# Add warden (<warden_folder>/bin/) to your $PATH according to your shell

Setting containers up

Basic Setup

Create the directory of the setup and init warden for magento2:

mkdir -p ~/cve2022-24086
cd ~/cve2022-24086

warden env-init cve2022-24086 magento2

Update the .env file with the following values:

nvim .env
PHP_VERSION=7.4
MYSQL_DISTRIBUTION_VERSION=10.4

# There is no opensearch on the target Magento version.
WARDEN_OPENSEARCH=0

Start warden support services Traeffik, Mailhog, DNSMasq and Tunnel with:

warden svc up

Generate certificates for magento services:

warden sign-certificate cve2022-24086.test

Start all magento services, and get a shell into the magento container

warden env up
warden shell

Composer Downgrade

We will install Magento 2.4.1 in a minute. For the installation to work, composer has to be downgraded to it’s version 1. In the Docker container, do:

sudo su
composer self-update --1
composer --version
# Composer version 1.10.26 2022-04-13 16:39:56

This solution was obtained from from this issue on composer’s GitHub.

Download Magento

From warden’s documentation. Be sure to specify the 2.4.1 magento version and copy/paste the following command in the magento container:

META_PACKAGE=magento/project-community-edition META_VERSION=2.4.1

composer create-project --repository-url=https://repo.magento.com/ \
    "${META_PACKAGE}" /tmp/exampleproject "${META_VERSION}"

rsync -a /tmp/exampleproject/ /var/www/html/
rm -rf /tmp/exampleproject/

Disable ElasticSearch

When setting up the instance, I had the error Could not validate a connection to Elasticsearch. No alive nodes found in your cluster. After trying to fix the problem, I stumbled upon this StackExchange post which describes a working, kind of barbaric fix: disabling Elasticsearch.

This can be done with the following command:

php bin/magento module:disable {Magento_Elasticsearch,Magento_InventoryElasticsearch,Magento_Elasticsearch6,Magento_Elasticsearch7}

Install Magento

Finish the setup with the following command. All references to openstack were removed from the original command because they do not exist on this Magento version:

bin/magento setup:install \
    --backend-frontname=backend \
    --amqp-host=rabbitmq \
    --amqp-port=5672 \
    --amqp-user=guest \
    --amqp-password=guest \
    --db-host=db \
    --db-name=magento \
    --db-user=magento \
    --db-password=magento \
    --http-cache-hosts=varnish:80 \
    --session-save=redis \
    --session-save-redis-host=redis \
    --session-save-redis-port=6379 \
    --session-save-redis-db=2 \
    --session-save-redis-max-concurrency=20 \
    --cache-backend=redis \
    --cache-backend-redis-server=redis \
    --cache-backend-redis-db=0 \
    --cache-backend-redis-port=6379 \
    --page-cache=redis \
    --page-cache-redis-server=redis \
    --page-cache-redis-db=1 \
    --page-cache-redis-port=6379

Then, configure the application (no changes were made from the warden docs available here 🥳):

bin/magento config:set --lock-env web/unsecure/base_url \
     "https://${TRAEFIK_SUBDOMAIN}.${TRAEFIK_DOMAIN}/"

bin/magento config:set --lock-env web/secure/base_url \
    "https://${TRAEFIK_SUBDOMAIN}.${TRAEFIK_DOMAIN}/"

bin/magento config:set --lock-env web/secure/offloader_header X-Forwarded-Proto

bin/magento config:set --lock-env web/secure/use_in_frontend 1
bin/magento config:set --lock-env web/secure/use_in_adminhtml 1
bin/magento config:set --lock-env web/seo/use_rewrites 1

bin/magento config:set --lock-env system/full_page_cache/caching_application 2
bin/magento config:set --lock-env system/full_page_cache/ttl 604800

bin/magento config:set --lock-env catalog/search/enable_eav_indexer 1

bin/magento config:set --lock-env dev/static/sign 0

bin/magento deploy:mode:set -s developer
bin/magento cache:disable block_html full_page

bin/magento indexer:reindex
bin/magento cache:flush

Add the following line to /etc/hosts:

127.0.0.1 app.cve2022-24086.test rabbitmq.cve2022-24086.test elasticsearch.cve2022-24086.test 
mailhog.warden.test dnsmasq.warden.test portainer.warden.test traefik.warden.test tunnel.warden.test

Generate the Magento administrator (small changes were made from the original warden command to fix python errors) :

ADMIN_PASS="superstrongpassword1234!"
ADMIN_USER=localadmin

bin/magento admin:user:create \
    --admin-password="${ADMIN_PASS}" \
    --admin-user="${ADMIN_USER}" \
    --admin-firstname="Local" \
    --admin-lastname="Admin" \
    --admin-email="${ADMIN_USER}@example.com"
printf "u: %s\np: %s\n" "${ADMIN_USER}" "${ADMIN_PASS}"

## Configure 2FA provider
OTPAUTH_QRI=
TFA_SECRET=$(python3 -c "import base64; print(base64.b32encode('$(pwgen -A1 128)'.encode('utf-8')).decode('utf-8'))" | sed 's/=*$//')
OTPAUTH_URL=$(printf "otpauth://totp/%s%%3Alocaladmin%%40example.com?issuer=%s&secret=%s" \
    "${TRAEFIK_SUBDOMAIN}.${TRAEFIK_DOMAIN}" "${TRAEFIK_SUBDOMAIN}.${TRAEFIK_DOMAIN}" "${TFA_SECRET}"
)

bin/magento config:set --lock-env twofactorauth/general/force_providers google
bin/magento security:tfa:google:set-secret "${ADMIN_USER}" "${TFA_SECRET}"

printf "%s\n\n" "${OTPAUTH_URL}"
printf "2FA Authenticator Codes:\n%s\n" "$(oathtool -s 30 -w 10 --totp --base32 "${TFA_SECRET}")"

segno "${OTPAUTH_URL}" -s 4 -o "pub/media/${ADMIN_USER}-totp-qr.png"
printf "%s\n\n" "https://${TRAEFIK_SUBDOMAIN}.${TRAEFIK_DOMAIN}/media/${ADMIN_USER}-totp-qr.png?t=$(date +%s)"

Access the Administrator Interface

The Magento administrator interface is now available at the URL https://app.cve2022-24086.test/backend with the credentials: localadmin:superstrongpassword1234!

After filling the correct credentials, a 2FA form to fill will appear.

Access the generated 2FA QRCode image and scan it with your Google Authenticator. The URL is generated by the previous command, and looks like: https://app.cve2022-24086.test/media/localadmin-totp-qr.png?t=1684930293

If you want to skip 2FA forever, you can disable it with the following command (tweaked from this StackExchange post):

bin/magento module:disable Magento_TwoFactorAuth --clear-static-content
bin/magento cache:flush
bin/magento setup:di:compile

Adding a Test Product

Add one product to the e-shop through the admin interface panel at https://app.cve2022-24086.test/backend. Go to CATALOG > Products and click the top-right button Add Product. Fill the form with an item you enjoy 😉.

In the New Product form, don’t forget to set the quantity to 999, and to click Save.

Consequences of Disabling ElasticSearch

As we disabled the ElasticSearch search engine, we can’t use the customer shop’s search bar without raising a PHP error. Therefore, we now have to display products on the main page through a widget, as described on this tutorial:

  1. Go to CONTENT/Page, grab the Home Page row and click on the Select action button > Edit
  2. In the opened page, click on Content which will deploy to show a wysiwyg editor.
  3. Click the lego-like “add widget” button of the wysiwyg editor. Set Widget Type to Catalog Products List and fill the form options.
  4. Click on Insert Widget and don’t forget to save! This sadly happens to me all the time 😭.

It works!

Try to add your made-up product to your cart and head to the shipping form at: https://app.cve2022-24086.test/checkout/#shipping

If it does not crash down, you are good 🚀!

Debugging Magento

PHPStorm Setup

Head to File > Settings > Server and add a server with the following settings:

Add a mapping from ~/cve2022-24086 to /var/www/html and check use path mapping.

Add a debug configuration under Run > Edit Configurations:

Click on the button Start listening for PHP Debug Connections: Listen to Debug Connections

Firefox Plugin

Install the Xdebug Firefox plugin(https://addons.mozilla.org/en-US/firefox/addon/xdebug-helper-for-firefox/) and set its preferences:

When you go to the page you want to debug, click on the little bug icon that is in the URL bar and select Debug:

Little Bug

Also, if you are proxifying your requests to and from Magento in Burp, check that you have XDEBUG_SESSION=PHPSTORM; in your cookies. Else, no breakpoint will ever be reached by your IDE.

Database Connection

See the following warden guide which has images for all database connection clients.

The Moment of Truth

Add a breakpoint at the start of the filter function within vendor/magento/module-email/Model/Template/Filter.php (for example, at the line $value = parent::filter($value)) and do a checkout workflow.

If execution is stopped, you are ready to go! Head to this blog post for the CVE-analysis

Troubleshooting

InnoDB Logs Errors

2023-05-24 11:46:42 0 [ERROR] InnoDB: Unsupported redo log format. The redo log was created with MariaDB 10.6.13.

This error happens if you did shenanigans with the warden .env file. Solution: Type warden env down, then docker volume ls, delete all volumes linked to cve2022-24086 and warden env up.

Composer Errors

Composer Could Not Be Written

[Composer\Downloader\FilesystemException]
  Filesystem exception:
  Composer update failed: "/usr/bin/composer" could not be written.
  rename(/usr/bin/composer): failed to open stream: Permission denied

You need to be super admin when downgrading composer. Do sudo su in the container before a downgrade.

Requirements Could Not Be Resolved

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Root composer.json requires dealerdirect/phpcodesniffer-composer-installer ^0.5.0 -> satisfiable by dealerdirect/phpcodesniffer-composer-installer[v0.5.0].
    - dealerdirect/phpcodesniffer-composer-installer v0.5.0 requires composer-plugin-api ^1.0 -> found composer-plugin-api[2.2.0] but it does not match the constraint.

You need to downgrade composer to version 1 😉

OpenSearch / ElasticSearch Errors

Exception/Warning: <Something happened with opensearch>

There is no opensearch bin/magento CLI options in the Magento version used in the setup. If you are using bin/magento commands, remove all references to opensearch.

Also, disable elasticsearch on the instance:

php bin/magento module:disable {Magento_Elasticsearch,Magento_InventoryElasticsearch,Magento_Elasticsearch6,Magento_Elasticsearch7}

app.cve2022-24086.test is Not Accessible

This could be a DNS issue. Try warden svc down and up again and check your /etc/hosts file. You might have forgotten to add app.cve2022-24086.test (yes, it’s easy to forget 🙉)

The Backend Admin SideBar Menu Stopped Working

Try the following commands from this Stack Exchange post:

cd pub/static
rm -rdf adminhtml frontend
cd -
bin/magento setup:static-content:deploy -f
bin/magento cache:flush

Disable the cache in Firefox and reload the admin interface.

If it all went to hell, nuke and redo the setup.

Applying And Reversing Patches For CVE-2022-24086

Do warden shell and head to the folder where the Magento store is installed (/var/www/html).

Download the patches for the CVE into the folder:

Execute the following command for each patch: patch < NAME_OF.patch.

The patch binary will fail to locate files to be patched and ask you for their location.

For patch MDVA-43395 it will look for:

  1. vendor/magento/module-email/Model/Template/Filter.php
  2. vendor/magento/framework/Filter/DirectiveProcessor/VarDirective.php

For patch MDVA-43443, it will look for:

  1. vendor/magento/module-email/Model/Template/Filter.php
  2. vendor/magento/framework/Filter/DirectiveProcessor/DependDirective.php
  3. vendor/magento/framework/Filter/DirectiveProcessor/ForDirective.php
  4. vendor/magento/framework/Filter/DirectiveProcessor/IfDirective.php
  5. vendor/magento/framework/Filter/DirectiveProcessor/SimpleDirective.php
  6. vendor/magento/framework/Filter/DirectiveProcessor/VarDirective.php

Reversing a patch is done through -R.

Closing Words

I hope you now have a functional setup. Have fun digging into Magento 🔥!