diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..70e3f54 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Deploy eCommerce Ltd. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Plugin/TrojanOrderPreventBillingAddress.php b/Plugin/TrojanOrderPreventBillingAddress.php new file mode 100644 index 0000000..8e634a1 --- /dev/null +++ b/Plugin/TrojanOrderPreventBillingAddress.php @@ -0,0 +1,85 @@ +state = $state; + $this->request = $request; + } + + /** + * Before assign billing address to cart + * + * This method is executed before the billing address is assigned to the cart. + * It checks the request body for specific strings that indicate a trojan order. + * If any of these strings are found, an AccessDeniedHttpException is thrown. + * + * @param BillingAddressManagementInterface $subject + * @param int $cartId + * @param AddressInterface $address + * @return array + * @throws AccessDeniedHttpException + */ + public function beforeAssign( + BillingAddressManagementInterface $subject, + $cartId, + AddressInterface $address + ) { + if ($this->state->getAreaCode() === \Magento\Framework\App\Area::AREA_WEBAPI_REST) { + $fields = $this->request->getBodyParams(); + + // Make sure we have an address key. + if (array_key_exists('address', $fields)) { + // For speed and ease of checking, flatten the array into a string. + $fields = strtolower(json_encode($fields)); + + // Iterate through our banned strings. + foreach ($this->strings_to_find as $string) { + if (strpos($fields, $string) !== false) { + throw new AccessDeniedHttpException('This request is not permitted.'); + } + } + } + } + + return [$cartId, $address]; + } +} diff --git a/Plugin/TrojanOrderPreventShippingAddress.php b/Plugin/TrojanOrderPreventShippingAddress.php new file mode 100644 index 0000000..5288e83 --- /dev/null +++ b/Plugin/TrojanOrderPreventShippingAddress.php @@ -0,0 +1,81 @@ +state = $state; + $this->request = $request; + } + + /** + * Before assign billing address to cart + * + * This method is executed before the billing address is assigned to the cart. + * It checks the request body for specific strings that indicate a trojan order. + * If any of these strings are found, an AccessDeniedHttpException is thrown. + * + * @param ShippingAddressManagementInterface $subject + * @param int $cartId + * @param AddressInterface $address + * @return array + * @throws AccessDeniedHttpException|\Magento\Framework\Exception\LocalizedException + */ + public function beforeAssign( + ShippingAddressManagementInterface $subject, + $cartId, + AddressInterface $address + ): array { + if ($this->state->getAreaCode() === \Magento\Framework\App\Area::AREA_WEBAPI_REST) { + $fields = $this->request->getBodyParams(); + + // For speed and ease of checking, flatten the array into a string. + $fields = strtolower(json_encode($fields)); + + // Iterate through our banned strings. + foreach ($this->strings_to_find as $string) { + if (strpos($fields, $string) !== false) { + throw new AccessDeniedHttpException('This request is not permitted.'); + } + } + } + + return [$cartId, $address]; + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..a12420b --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +# module-trojan-order-prevent + +This is a Magento 2 extension that prevents billing/shipping addresses being +saved via the API with known trojan order strings. This is *not a fix* for +CVE-2022-24086 but an additional layer of protection for merchants. + +Although patched in most recent Magento versions we still see probes for this +which look rather unsightly for merchants in the orders screen of Magento. + +This module adds two plugins to the `Magento\Quote\Api\BillingAddressManagementInterface` +and the `Magento\Quote\Model\ShippingAddressManagementInterface` to prevent the +saving of addresses with the following strings: + +``` +gettemplate +base64_ +afterfiltercall +``` +If these are detected in the payload then an Exception is thrown and the address is not saved. + +### Installation +```bash +composer require deployecommerce/module-trojan-order-prevent +bin/magento mo:e DeployEcommerce_TrojanOrderPrevent +``` + +### Further Reading +- https://sansec.io/research/trojanorder-magento +- https://www.bleepingcomputer.com/news/security/magento-stores-targeted-in-massive-surge-of-trojanorders-attacks/ +- https://cyberfraudcentre.com/surge-in-trojanorders-attacks-on-magento-2-e-commerce-sites +- https://magento.stackexchange.com/questions/358839/magento-2-fake-customer-order-came-through-with-weird-code-instead-of-customer +- https://github.com/magento/magento2/issues/36691 + +### License + +This module is licensed under the MIT License. See the [LICENSE](LICENSE.md) file for details. \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..62ca230 --- /dev/null +++ b/composer.json @@ -0,0 +1,22 @@ +{ + "name": "deployecommerce/module-trojan-order-prevent", + "description": "A Magento2 extension that prevents billing/shipping addresses being saved via the API with known trojan order strings.", + "type": "magento2-module", + "authors": [ + { + "name": "Deploy", + "email": "hello@deploy.co.uk", + "role": "Agency" + } + ], + "require": {}, + "license": "MIT", + "autoload": { + "psr-4": { + "DeployEcommerce\\TrojanOrderPrevent\\": "" + }, + "files": [ + "registration.php" + ] + } +} diff --git a/etc/di.xml b/etc/di.xml new file mode 100644 index 0000000..b6519bc --- /dev/null +++ b/etc/di.xml @@ -0,0 +1,13 @@ + + + + + + + + + + \ No newline at end of file diff --git a/etc/module.xml b/etc/module.xml new file mode 100644 index 0000000..51d4e1a --- /dev/null +++ b/etc/module.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/registration.php b/registration.php new file mode 100644 index 0000000..b671a31 --- /dev/null +++ b/registration.php @@ -0,0 +1,6 @@ +